aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/.may_include2
-rw-r--r--src/test/Makefile.nmake8
-rw-r--r--src/test/bench.c121
-rwxr-xr-xsrc/test/bt_test.py4
-rw-r--r--src/test/conf_examples/badnick_1/error1
-rw-r--r--src/test/conf_examples/badnick_1/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/badnick_1/expected_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/badnick_1/torrc4
-rw-r--r--src/test/conf_examples/badnick_2/error1
-rw-r--r--src/test/conf_examples/badnick_2/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/badnick_2/expected_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/badnick_2/torrc4
-rw-r--r--src/test/conf_examples/bridgeauth_1/error_no_dirauth1
-rw-r--r--src/test/conf_examples/bridgeauth_1/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/bridgeauth_1/expected7
-rw-r--r--src/test/conf_examples/bridgeauth_1/expected_log1
-rw-r--r--src/test/conf_examples/bridgeauth_1/torrc8
-rw-r--r--src/test/conf_examples/bug_31495_1/expected2
-rw-r--r--src/test/conf_examples/bug_31495_1/expected_log1
-rw-r--r--src/test/conf_examples/bug_31495_1/torrc2
-rw-r--r--src/test/conf_examples/bug_31495_2/error1
-rw-r--r--src/test/conf_examples/bug_31495_2/torrc3
-rw-r--r--src/test/conf_examples/bug_31495_3/cmdline1
-rw-r--r--src/test/conf_examples/bug_31495_3/expected2
-rw-r--r--src/test/conf_examples/bug_31495_3/expected_log1
-rw-r--r--src/test/conf_examples/bug_31495_3/torrc3
-rw-r--r--src/test/conf_examples/contactinfo_notutf8/error1
-rw-r--r--src/test/conf_examples/contactinfo_notutf8/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/contactinfo_notutf8/expected_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/contactinfo_notutf8/torrc5
-rw-r--r--src/test/conf_examples/controlsock/error1
-rw-r--r--src/test/conf_examples/controlsock/torrc1
-rw-r--r--src/test/conf_examples/crypto_accel/expected2
-rw-r--r--src/test/conf_examples/crypto_accel/expected_log1
-rw-r--r--src/test/conf_examples/crypto_accel/expected_log_nss1
-rw-r--r--src/test/conf_examples/crypto_accel/expected_nss2
-rw-r--r--src/test/conf_examples/crypto_accel/torrc3
-rw-r--r--src/test/conf_examples/crypto_accel_req/error1
-rw-r--r--src/test/conf_examples/crypto_accel_req/expected_log_nss1
-rw-r--r--src/test/conf_examples/crypto_accel_req/expected_nss2
-rw-r--r--src/test/conf_examples/crypto_accel_req/torrc3
-rw-r--r--src/test/conf_examples/dirauth_1/error_no_dirauth1
-rw-r--r--src/test/conf_examples/dirauth_1/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/dirauth_1/expected8
-rw-r--r--src/test/conf_examples/dirauth_1/expected_log1
-rw-r--r--src/test/conf_examples/dirauth_1/torrc8
-rw-r--r--src/test/conf_examples/dirauth_2/expected1
-rw-r--r--src/test/conf_examples/dirauth_2/expected_log1
-rw-r--r--src/test/conf_examples/dirauth_2/expected_log_no_dirauth1
-rw-r--r--src/test/conf_examples/dirauth_2/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/dirauth_2/expected_no_dirauth0
-rw-r--r--src/test/conf_examples/dirauth_2/expected_no_dirauth_relay0
-rw-r--r--src/test/conf_examples/dirauth_2/torrc5
-rw-r--r--src/test/conf_examples/dirauth_3/error_no_dirauth1
-rw-r--r--src/test/conf_examples/dirauth_3/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/dirauth_3/expected9
-rw-r--r--src/test/conf_examples/dirauth_3/expected_log1
-rw-r--r--src/test/conf_examples/dirauth_3/torrc13
-rw-r--r--src/test/conf_examples/empty_1/expected0
-rw-r--r--src/test/conf_examples/empty_1/expected_log1
-rw-r--r--src/test/conf_examples/empty_1/torrc0
-rw-r--r--src/test/conf_examples/empty_2/cmdline0
-rw-r--r--src/test/conf_examples/empty_2/expected0
-rw-r--r--src/test/conf_examples/empty_2/expected_log1
-rw-r--r--src/test/conf_examples/empty_2/torrc0
-rw-r--r--src/test/conf_examples/empty_2/torrc.defaults0
-rw-r--r--src/test/conf_examples/empty_3/expected0
-rw-r--r--src/test/conf_examples/empty_3/expected_log1
-rw-r--r--src/test/conf_examples/empty_3/included/empty0
-rw-r--r--src/test/conf_examples/empty_3/torrc1
-rw-r--r--src/test/conf_examples/empty_4/error1
-rw-r--r--src/test/conf_examples/example_1/expected2
-rw-r--r--src/test/conf_examples/example_1/expected_log1
-rw-r--r--src/test/conf_examples/example_1/torrc5
-rw-r--r--src/test/conf_examples/example_2/error1
-rw-r--r--src/test/conf_examples/example_2/torrc1
-rw-r--r--src/test/conf_examples/example_3/cmdline1
-rw-r--r--src/test/conf_examples/example_3/expected1
-rw-r--r--src/test/conf_examples/example_3/expected_log1
-rw-r--r--src/test/conf_examples/example_3/torrc0
-rw-r--r--src/test/conf_examples/include_1/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/include_1/expected3
-rw-r--r--src/test/conf_examples/include_1/expected_log1
-rw-r--r--src/test/conf_examples/include_1/included.inc4
-rw-r--r--src/test/conf_examples/include_1/nested.inc2
-rw-r--r--src/test/conf_examples/include_1/torrc4
-rw-r--r--src/test/conf_examples/include_bug_31408/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/include_bug_31408/expected2
-rw-r--r--src/test/conf_examples/include_bug_31408/expected_log1
-rw-r--r--src/test/conf_examples/include_bug_31408/included/01_nickname.inc1
-rw-r--r--src/test/conf_examples/include_bug_31408/included/02_no_configs.inc3
-rw-r--r--src/test/conf_examples/include_bug_31408/torrc2
-rw-r--r--src/test/conf_examples/large_1/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/large_1/expected156
-rw-r--r--src/test/conf_examples/large_1/expected_log1
-rw-r--r--src/test/conf_examples/large_1/expected_log_no_dirauth1
-rw-r--r--src/test/conf_examples/large_1/expected_no_dirauth155
-rw-r--r--src/test/conf_examples/large_1/torrc165
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected0
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log1
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log_lzma1
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd1
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log_zstd1
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_lzma0
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_lzma_zstd0
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_zstd0
-rw-r--r--src/test/conf_examples/lzma_zstd_1/torrc1
-rw-r--r--src/test/conf_examples/missing_cl_arg/cmdline1
-rw-r--r--src/test/conf_examples/missing_cl_arg/error1
-rw-r--r--src/test/conf_examples/missing_cl_arg/torrc0
-rw-r--r--src/test/conf_examples/multiple_routerset_1/expected1
-rw-r--r--src/test/conf_examples/multiple_routerset_1/expected_log1
-rw-r--r--src/test/conf_examples/multiple_routerset_1/torrc2
-rw-r--r--src/test/conf_examples/multiple_routerset_2/cmdline1
-rw-r--r--src/test/conf_examples/multiple_routerset_2/expected1
-rw-r--r--src/test/conf_examples/multiple_routerset_2/expected_log1
-rw-r--r--src/test/conf_examples/multiple_routerset_2/torrc2
-rw-r--r--src/test/conf_examples/multiple_routerset_3/cmdline1
-rw-r--r--src/test/conf_examples/multiple_routerset_3/expected1
-rw-r--r--src/test/conf_examples/multiple_routerset_3/expected_log1
-rw-r--r--src/test/conf_examples/multiple_routerset_3/torrc2
-rw-r--r--src/test/conf_examples/multiple_routerset_4/cmdline1
-rw-r--r--src/test/conf_examples/multiple_routerset_4/expected1
-rw-r--r--src/test/conf_examples/multiple_routerset_4/expected_log1
-rw-r--r--src/test/conf_examples/multiple_routerset_4/torrc3
-rw-r--r--src/test/conf_examples/nss_1/expected0
-rw-r--r--src/test/conf_examples/nss_1/expected_log1
-rw-r--r--src/test/conf_examples/nss_1/expected_log_nss1
-rw-r--r--src/test/conf_examples/nss_1/expected_nss0
-rw-r--r--src/test/conf_examples/nss_1/torrc1
-rw-r--r--src/test/conf_examples/obsolete_1/expected0
-rw-r--r--src/test/conf_examples/obsolete_1/expected_log1
-rw-r--r--src/test/conf_examples/obsolete_1/torrc70
-rw-r--r--src/test/conf_examples/obsolete_2/expected0
-rw-r--r--src/test/conf_examples/obsolete_2/expected_log1
-rw-r--r--src/test/conf_examples/obsolete_2/torrc5
-rw-r--r--src/test/conf_examples/obsolete_3/expected0
-rw-r--r--src/test/conf_examples/obsolete_3/expected_log1
-rw-r--r--src/test/conf_examples/obsolete_3/torrc4
-rw-r--r--src/test/conf_examples/ops_1/cmdline1
-rw-r--r--src/test/conf_examples/ops_1/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/ops_1/expected2
-rw-r--r--src/test/conf_examples/ops_1/expected_log1
-rw-r--r--src/test/conf_examples/ops_1/torrc3
-rw-r--r--src/test/conf_examples/ops_2/cmdline1
-rw-r--r--src/test/conf_examples/ops_2/expected0
-rw-r--r--src/test/conf_examples/ops_2/expected_log1
-rw-r--r--src/test/conf_examples/ops_2/torrc3
-rw-r--r--src/test/conf_examples/ops_3/cmdline1
-rw-r--r--src/test/conf_examples/ops_3/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/ops_3/expected3
-rw-r--r--src/test/conf_examples/ops_3/expected_log1
-rw-r--r--src/test/conf_examples/ops_3/torrc3
-rw-r--r--src/test/conf_examples/ops_4/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/ops_4/expected2
-rw-r--r--src/test/conf_examples/ops_4/expected_log1
-rw-r--r--src/test/conf_examples/ops_4/torrc3
-rw-r--r--src/test/conf_examples/ops_4/torrc.defaults1
-rw-r--r--src/test/conf_examples/ops_5/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/ops_5/expected3
-rw-r--r--src/test/conf_examples/ops_5/expected_log1
-rw-r--r--src/test/conf_examples/ops_5/torrc3
-rw-r--r--src/test/conf_examples/ops_5/torrc.defaults1
-rw-r--r--src/test/conf_examples/ops_6/expected0
-rw-r--r--src/test/conf_examples/ops_6/expected_log1
-rw-r--r--src/test/conf_examples/ops_6/torrc3
-rw-r--r--src/test/conf_examples/ops_6/torrc.defaults1
-rw-r--r--src/test/conf_examples/pt_01/expected0
-rw-r--r--src/test/conf_examples/pt_01/expected_log1
-rw-r--r--src/test/conf_examples/pt_01/torrc7
-rw-r--r--src/test/conf_examples/pt_02/error1
-rw-r--r--src/test/conf_examples/pt_02/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_02/expected_no_dirauth_relay8
-rw-r--r--src/test/conf_examples/pt_02/torrc13
-rw-r--r--src/test/conf_examples/pt_03/expected1
-rw-r--r--src/test/conf_examples/pt_03/expected_log1
-rw-r--r--src/test/conf_examples/pt_03/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_03/expected_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_03/torrc4
-rw-r--r--src/test/conf_examples/pt_04/expected3
-rw-r--r--src/test/conf_examples/pt_04/expected_log1
-rw-r--r--src/test/conf_examples/pt_04/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_04/expected_no_dirauth_relay3
-rw-r--r--src/test/conf_examples/pt_04/torrc6
-rw-r--r--src/test/conf_examples/pt_05/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_05/expected4
-rw-r--r--src/test/conf_examples/pt_05/expected_log1
-rw-r--r--src/test/conf_examples/pt_05/torrc6
-rw-r--r--src/test/conf_examples/pt_06/expected6
-rw-r--r--src/test/conf_examples/pt_06/expected_log1
-rw-r--r--src/test/conf_examples/pt_06/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_06/expected_no_dirauth_relay6
-rw-r--r--src/test/conf_examples/pt_06/torrc9
-rw-r--r--src/test/conf_examples/pt_07/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_07/expected4
-rw-r--r--src/test/conf_examples/pt_07/expected_log1
-rw-r--r--src/test/conf_examples/pt_07/torrc6
-rw-r--r--src/test/conf_examples/pt_08/error1
-rw-r--r--src/test/conf_examples/pt_08/expected_log_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_08/expected_no_dirauth_relay2
-rw-r--r--src/test/conf_examples/pt_08/torrc7
-rw-r--r--src/test/conf_examples/pt_09/error1
-rw-r--r--src/test/conf_examples/pt_09/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/pt_09/torrc7
-rw-r--r--src/test/conf_examples/relay_01/expected0
-rw-r--r--src/test/conf_examples/relay_01/expected_log1
-rw-r--r--src/test/conf_examples/relay_01/torrc5
-rw-r--r--src/test/conf_examples/relay_02/error1
-rw-r--r--src/test/conf_examples/relay_02/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_02/torrc7
-rw-r--r--src/test/conf_examples/relay_03/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_03/expected2
-rw-r--r--src/test/conf_examples/relay_03/expected_log1
-rw-r--r--src/test/conf_examples/relay_03/torrc5
-rw-r--r--src/test/conf_examples/relay_04/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_04/expected2
-rw-r--r--src/test/conf_examples/relay_04/expected_log1
-rw-r--r--src/test/conf_examples/relay_04/torrc4
-rw-r--r--src/test/conf_examples/relay_05/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_05/expected3
-rw-r--r--src/test/conf_examples/relay_05/expected_log1
-rw-r--r--src/test/conf_examples/relay_05/torrc5
-rw-r--r--src/test/conf_examples/relay_06/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_06/expected3
-rw-r--r--src/test/conf_examples/relay_06/expected_log1
-rw-r--r--src/test/conf_examples/relay_06/torrc5
-rw-r--r--src/test/conf_examples/relay_07/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_07/expected3
-rw-r--r--src/test/conf_examples/relay_07/expected_log1
-rw-r--r--src/test/conf_examples/relay_07/torrc5
-rw-r--r--src/test/conf_examples/relay_08/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_08/expected3
-rw-r--r--src/test/conf_examples/relay_08/expected_log1
-rw-r--r--src/test/conf_examples/relay_08/torrc6
-rw-r--r--src/test/conf_examples/relay_09/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_09/expected3
-rw-r--r--src/test/conf_examples/relay_09/expected_log1
-rw-r--r--src/test/conf_examples/relay_09/torrc6
-rw-r--r--src/test/conf_examples/relay_10/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_10/expected3
-rw-r--r--src/test/conf_examples/relay_10/expected_log1
-rw-r--r--src/test/conf_examples/relay_10/torrc7
-rw-r--r--src/test/conf_examples/relay_11/error1
-rw-r--r--src/test/conf_examples/relay_11/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_11/torrc4
-rw-r--r--src/test/conf_examples/relay_12/error1
-rw-r--r--src/test/conf_examples/relay_12/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_12/torrc4
-rw-r--r--src/test/conf_examples/relay_13/error1
-rw-r--r--src/test/conf_examples/relay_13/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_13/torrc4
-rw-r--r--src/test/conf_examples/relay_14/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_14/expected1
-rw-r--r--src/test/conf_examples/relay_14/expected_log1
-rw-r--r--src/test/conf_examples/relay_14/torrc4
-rw-r--r--src/test/conf_examples/relay_15/error1
-rw-r--r--src/test/conf_examples/relay_15/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_15/torrc5
-rw-r--r--src/test/conf_examples/relay_16/error1
-rw-r--r--src/test/conf_examples/relay_16/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_16/torrc4
-rw-r--r--src/test/conf_examples/relay_17/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_17/expected4
-rw-r--r--src/test/conf_examples/relay_17/expected_log1
-rw-r--r--src/test/conf_examples/relay_17/torrc6
-rw-r--r--src/test/conf_examples/relay_18/error1
-rw-r--r--src/test/conf_examples/relay_18/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_18/torrc4
-rw-r--r--src/test/conf_examples/relay_19/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_19/expected3
-rw-r--r--src/test/conf_examples/relay_19/expected_log1
-rw-r--r--src/test/conf_examples/relay_19/torrc5
-rw-r--r--src/test/conf_examples/relay_20/error1
-rw-r--r--src/test/conf_examples/relay_20/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_20/torrc5
-rw-r--r--src/test/conf_examples/relay_21/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_21/expected3
-rw-r--r--src/test/conf_examples/relay_21/expected_log1
-rw-r--r--src/test/conf_examples/relay_21/torrc5
-rw-r--r--src/test/conf_examples/relay_22/error1
-rw-r--r--src/test/conf_examples/relay_22/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_22/torrc6
-rw-r--r--src/test/conf_examples/relay_23/error1
-rw-r--r--src/test/conf_examples/relay_23/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_23/torrc5
-rw-r--r--src/test/conf_examples/relay_24/error1
-rw-r--r--src/test/conf_examples/relay_24/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_24/torrc5
-rw-r--r--src/test/conf_examples/relay_25/error1
-rw-r--r--src/test/conf_examples/relay_25/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_25/torrc5
-rw-r--r--src/test/conf_examples/relay_26/error1
-rw-r--r--src/test/conf_examples/relay_26/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_26/torrc5
-rw-r--r--src/test/conf_examples/relay_27/error1
-rw-r--r--src/test/conf_examples/relay_27/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_27/torrc5
-rw-r--r--src/test/conf_examples/relay_28/error1
-rw-r--r--src/test/conf_examples/relay_28/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_28/torrc5
-rw-r--r--src/test/conf_examples/relay_29/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_29/expected2
-rw-r--r--src/test/conf_examples/relay_29/expected_log1
-rw-r--r--src/test/conf_examples/relay_29/torrc5
-rw-r--r--src/test/conf_examples/relay_30/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_30/expected2
-rw-r--r--src/test/conf_examples/relay_30/expected_log1
-rw-r--r--src/test/conf_examples/relay_30/torrc3
-rw-r--r--src/test/conf_examples/relay_31/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_31/expected3
-rw-r--r--src/test/conf_examples/relay_31/expected_log1
-rw-r--r--src/test/conf_examples/relay_31/torrc4
-rw-r--r--src/test/conf_examples/relay_32/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_32/expected3
-rw-r--r--src/test/conf_examples/relay_32/expected_log1
-rw-r--r--src/test/conf_examples/relay_32/torrc4
-rw-r--r--src/test/conf_examples/relay_33/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_33/expected3
-rw-r--r--src/test/conf_examples/relay_33/expected_log1
-rw-r--r--src/test/conf_examples/relay_33/torrc4
-rw-r--r--src/test/conf_examples/relay_34/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_34/expected4
-rw-r--r--src/test/conf_examples/relay_34/expected_log1
-rw-r--r--src/test/conf_examples/relay_34/torrc5
-rw-r--r--src/test/conf_examples/relpath_rad/error1
-rw-r--r--src/test/conf_examples/relpath_rad/torrc4
-rw-r--r--src/test/conf_failures/README5
-rw-r--r--src/test/conf_failures/fail-error-success/error1
-rw-r--r--src/test/conf_failures/fail-error-success/torrc0
-rw-r--r--src/test/conf_failures/fail-error/error1
-rw-r--r--src/test/conf_failures/fail-error/torrc1
-rw-r--r--src/test/conf_failures/fail-expected-error/expected0
-rw-r--r--src/test/conf_failures/fail-expected-error/torrc1
-rw-r--r--src/test/conf_failures/fail-expected-log/expected0
-rw-r--r--src/test/conf_failures/fail-expected-log/expected_log1
-rw-r--r--src/test/conf_failures/fail-expected-log/torrc0
-rw-r--r--src/test/conf_failures/fail-expected/expected1
-rw-r--r--src/test/conf_failures/fail-expected/torrc0
-rw-r--r--src/test/ed25519_exts_ref.py31
-rw-r--r--src/test/example_extrainfo.inc505
-rw-r--r--src/test/example_extrainfo.template182
-rw-r--r--src/test/failing_routerdescs.inc1840
-rw-r--r--src/test/failing_routerdescs.template812
-rw-r--r--src/test/fakechans.h2
-rw-r--r--src/test/fakecircs.c91
-rw-r--r--src/test/fakecircs.h17
-rw-r--r--src/test/fuzz/.may_include1
-rwxr-xr-xsrc/test/fuzz/fixup_filenames.sh6
-rw-r--r--src/test/fuzz/fuzz_consensus.c8
-rw-r--r--src/test/fuzz/fuzz_descriptor.c2
-rw-r--r--src/test/fuzz/fuzz_diff.c34
-rw-r--r--src/test/fuzz/fuzz_diff_apply.c15
-rw-r--r--src/test/fuzz/fuzz_extrainfo.c2
-rw-r--r--src/test/fuzz/fuzz_hsdescv2.c2
-rw-r--r--src/test/fuzz/fuzz_hsdescv3.c20
-rw-r--r--src/test/fuzz/fuzz_http.c4
-rw-r--r--src/test/fuzz/fuzz_http_connect.c4
-rw-r--r--src/test/fuzz/fuzz_iptsv2.c2
-rw-r--r--src/test/fuzz/fuzz_microdesc.c2
-rwxr-xr-xsrc/test/fuzz/fuzz_multi.sh6
-rw-r--r--src/test/fuzz/fuzz_socks.c4
-rw-r--r--src/test/fuzz/fuzz_strops.c253
-rw-r--r--src/test/fuzz/fuzz_vrs.c26
-rw-r--r--src/test/fuzz/fuzzing.h4
-rw-r--r--src/test/fuzz/fuzzing_common.c23
-rw-r--r--src/test/fuzz/include.am38
-rwxr-xr-xsrc/test/fuzz/minimize.sh2
-rwxr-xr-xsrc/test/fuzz_static_testcases.sh2
-rw-r--r--src/test/hs_build_address.py5
-rw-r--r--src/test/hs_indexes.py5
-rw-r--r--src/test/hs_ntor_ref.py5
-rw-r--r--src/test/hs_test_helpers.c212
-rw-r--r--src/test/hs_test_helpers.h24
-rw-r--r--src/test/include.am142
-rw-r--r--src/test/log_test_helpers.c2
-rw-r--r--src/test/log_test_helpers.h18
-rwxr-xr-xsrc/test/ntor_ref.py7
-rw-r--r--src/test/ope_ref.py7
-rw-r--r--src/test/opts_test_helpers.c38
-rw-r--r--src/test/opts_test_helpers.h22
-rw-r--r--src/test/prob_distr_mpfr_ref.c64
-rw-r--r--src/test/ptr_helpers.c50
-rw-r--r--src/test/ptr_helpers.h23
-rw-r--r--src/test/rend_test_helpers.c15
-rw-r--r--src/test/rend_test_helpers.h2
-rw-r--r--src/test/resolve_test_helpers.c85
-rw-r--r--src/test/resolve_test_helpers.h18
-rw-r--r--src/test/rng_test_helpers.c259
-rw-r--r--src/test/rng_test_helpers.h25
-rw-r--r--src/test/slow_ed25519.py32
-rw-r--r--src/test/slownacl_curve25519.py7
-rw-r--r--src/test/sr_commit_calc_ref.py5
-rw-r--r--src/test/sr_srv_calc_ref.py5
-rw-r--r--src/test/test-child.c61
-rw-r--r--src/test/test-memwipe.c27
-rwxr-xr-xsrc/test/test-network.sh48
-rw-r--r--src/test/test-process.c85
-rw-r--r--src/test/test-timers.c4
-rw-r--r--src/test/test.c256
-rw-r--r--src/test/test.h160
-rw-r--r--src/test/test_accounting.c18
-rw-r--r--src/test/test_addr.c834
-rw-r--r--src/test/test_address.c180
-rw-r--r--src/test/test_address_set.c34
-rw-r--r--src/test/test_bridges.c16
-rwxr-xr-xsrc/test/test_bt.sh2
-rw-r--r--src/test/test_bt_cl.c16
-rw-r--r--src/test/test_btrack.c129
-rw-r--r--src/test/test_buffers.c4
-rw-r--r--src/test/test_bwmgt.c219
-rw-r--r--src/test/test_cell_formats.c80
-rw-r--r--src/test/test_cell_queue.c2
-rw-r--r--src/test/test_channel.c149
-rw-r--r--src/test/test_channelpadding.c13
-rw-r--r--src/test/test_channeltls.c41
-rw-r--r--src/test/test_checkdir.c2
-rw-r--r--src/test/test_circuitbuild.c1828
-rw-r--r--src/test/test_circuitlist.c6
-rw-r--r--src/test/test_circuitmux.c395
-rw-r--r--src/test/test_circuitmux_ewma.c228
-rw-r--r--src/test/test_circuitpadding.c3148
-rw-r--r--src/test/test_circuitstats.c101
-rw-r--r--src/test/test_circuituse.c2
-rwxr-xr-xsrc/test/test_cmdline.sh65
-rw-r--r--src/test/test_compat_libevent.c7
-rw-r--r--src/test/test_config.c2264
-rw-r--r--src/test/test_confmgr.c499
-rw-r--r--src/test/test_confparse.c1091
-rw-r--r--src/test/test_connection.c228
-rw-r--r--src/test/test_connection.h9
-rw-r--r--src/test/test_conscache.c2
-rw-r--r--src/test/test_consdiff.c110
-rw-r--r--src/test/test_consdiffmgr.c49
-rw-r--r--src/test/test_containers.c92
-rw-r--r--src/test/test_controller.c711
-rw-r--r--src/test/test_controller_events.c381
-rw-r--r--src/test/test_crypto.c225
-rw-r--r--src/test/test_crypto_ope.c2
-rw-r--r--src/test/test_crypto_openssl.c2
-rw-r--r--src/test/test_crypto_rng.c332
-rw-r--r--src/test/test_crypto_slow.c8
-rw-r--r--src/test/test_data.c2
-rw-r--r--src/test/test_descriptors.inc734
-rw-r--r--src/test/test_dir.c2153
-rw-r--r--src/test/test_dir_common.c67
-rw-r--r--src/test/test_dir_common.h6
-rw-r--r--src/test/test_dir_handle_get.c473
-rw-r--r--src/test/test_dirvote.c671
-rw-r--r--src/test/test_dispatch.c278
-rw-r--r--src/test/test_dns.c249
-rw-r--r--src/test/test_dos.c38
-rw-r--r--src/test/test_entryconn.c4
-rw-r--r--src/test/test_entrynodes.c238
-rw-r--r--src/test/test_extorport.c37
-rw-r--r--src/test/test_geoip.c8
-rw-r--r--src/test/test_guardfraction.c8
-rw-r--r--src/test/test_handles.c2
-rw-r--r--src/test/test_helpers.c292
-rw-r--r--src/test/test_helpers.h18
-rw-r--r--src/test/test_hs.c18
-rw-r--r--src/test/test_hs_cache.c190
-rw-r--r--src/test/test_hs_cell.c102
-rw-r--r--src/test/test_hs_client.c636
-rw-r--r--src/test/test_hs_common.c88
-rw-r--r--src/test/test_hs_config.c134
-rw-r--r--src/test/test_hs_control.c569
-rw-r--r--src/test/test_hs_descriptor.c231
-rw-r--r--src/test/test_hs_dos.c176
-rw-r--r--src/test/test_hs_intropoint.c231
-rw-r--r--src/test/test_hs_metrics.c68
-rw-r--r--src/test/test_hs_ntor.c10
-rwxr-xr-xsrc/test/test_hs_ntor.sh2
-rw-r--r--src/test/test_hs_ntor_cl.c18
-rw-r--r--src/test/test_hs_ob.c268
-rw-r--r--src/test/test_hs_service.c721
-rw-r--r--src/test/test_include.py196
-rwxr-xr-xsrc/test/test_include.sh111
-rw-r--r--src/test/test_introduce.c5
-rwxr-xr-xsrc/test/test_key_expiration.sh110
-rwxr-xr-xsrc/test/test_keygen.sh70
-rw-r--r--src/test/test_keypin.c2
-rw-r--r--src/test/test_link_handshake.c23
-rw-r--r--src/test/test_logging.c34
-rw-r--r--src/test/test_mainloop.c243
-rw-r--r--src/test/test_metrics.c277
-rw-r--r--src/test/test_microdesc.c326
-rw-r--r--src/test/test_namemap.c174
-rw-r--r--src/test/test_netinfo.c48
-rw-r--r--src/test/test_nodelist.c1213
-rw-r--r--src/test/test_ntor_cl.c2
-rw-r--r--src/test/test_oom.c4
-rw-r--r--src/test/test_oos.c2
-rw-r--r--src/test/test_options.c2191
-rw-r--r--src/test/test_options_act.c272
-rw-r--r--src/test/test_parsecommon.c594
-rwxr-xr-xsrc/test/test_parseconf.sh655
-rw-r--r--src/test/test_pem.c2
-rw-r--r--src/test/test_periodic_event.c111
-rw-r--r--src/test/test_policy.c444
-rw-r--r--src/test/test_prob_distr.c1406
-rw-r--r--src/test/test_process.c669
-rw-r--r--src/test/test_process_descs.c70
-rw-r--r--src/test/test_process_slow.c365
-rw-r--r--src/test/test_procmon.c5
-rw-r--r--src/test/test_proto_haproxy.c66
-rw-r--r--src/test/test_proto_http.c4
-rw-r--r--src/test/test_proto_misc.c4
-rw-r--r--src/test/test_protover.c430
-rw-r--r--src/test/test_pt.c136
-rw-r--r--src/test/test_ptr_slow.c106
-rw-r--r--src/test/test_pubsub_build.c578
-rw-r--r--src/test/test_pubsub_msg.c305
-rw-r--r--src/test/test_rebind.py10
-rwxr-xr-xsrc/test/test_rebind.sh46
-rw-r--r--src/test/test_relay.c230
-rw-r--r--src/test/test_relaycell.c36
-rw-r--r--src/test/test_relaycrypt.c12
-rw-r--r--src/test/test_rendcache.c42
-rw-r--r--src/test/test_replay.c2
-rw-r--r--src/test/test_rng.c59
-rw-r--r--src/test/test_router.c402
-rw-r--r--src/test/test_routerkeys.c68
-rw-r--r--src/test/test_routerlist.c72
-rw-r--r--src/test/test_routerset.c1087
-rwxr-xr-xsrc/test/test_rust.sh5
-rw-r--r--src/test/test_scheduler.c60
-rw-r--r--src/test/test_sendme.c365
-rw-r--r--src/test/test_shared_random.c410
-rw-r--r--src/test/test_slow.c6
-rw-r--r--src/test/test_socks.c41
-rw-r--r--src/test/test_statefile.c56
-rw-r--r--src/test/test_stats.c592
-rw-r--r--src/test/test_status.c823
-rw-r--r--src/test/test_storagedir.c2
-rw-r--r--src/test/test_switch_id.c4
-rwxr-xr-xsrc/test/test_switch_id.sh4
-rw-r--r--src/test/test_threads.c4
-rw-r--r--src/test/test_token_bucket.c152
-rw-r--r--src/test/test_tortls.c10
-rw-r--r--src/test/test_tortls.h4
-rw-r--r--src/test/test_tortls_openssl.c14
-rw-r--r--src/test/test_util.c1281
-rw-r--r--src/test/test_util_format.c15
-rw-r--r--src/test/test_util_process.c11
-rw-r--r--src/test/test_util_slow.c396
-rw-r--r--src/test/test_voting_flags.c193
-rw-r--r--src/test/test_voting_schedule.c8
-rw-r--r--src/test/test_workqueue.c12
-rwxr-xr-xsrc/test/test_workqueue_cancel.sh2
-rwxr-xr-xsrc/test/test_workqueue_efd.sh2
-rwxr-xr-xsrc/test/test_workqueue_efd2.sh2
-rwxr-xr-xsrc/test/test_workqueue_pipe.sh2
-rwxr-xr-xsrc/test/test_workqueue_pipe2.sh2
-rwxr-xr-xsrc/test/test_workqueue_socketpair.sh2
-rw-r--r--src/test/test_x509.c2
-rwxr-xr-xsrc/test/test_zero_length_keys.sh40
-rw-r--r--src/test/testing_common.c52
-rw-r--r--src/test/testing_rsakeys.c7
-rw-r--r--src/test/vote_descriptors.inc8
-rwxr-xr-xsrc/test/zero_length_keys.sh6
560 files changed, 38699 insertions, 8496 deletions
diff --git a/src/test/.may_include b/src/test/.may_include
new file mode 100644
index 0000000000..11c5ffbb14
--- /dev/null
+++ b/src/test/.may_include
@@ -0,0 +1,2 @@
+*.h
+*.inc
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake
index cfbe281b94..ca6a84cf8a 100644
--- a/src/test/Makefile.nmake
+++ b/src/test/Makefile.nmake
@@ -1,4 +1,4 @@
-all: test.exe test-child.exe bench.exe
+all: test.exe bench.exe
CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common /I ..\or \
/I ..\ext
@@ -19,6 +19,7 @@ TEST_OBJECTS = test.obj test_addr.obj test_channel.obj test_channeltls.obj \
test_cell_formats.obj test_relay.obj test_replay.obj \
test_channelpadding.obj \
test_circuitstats.obj \
+ test_circuitpadding.obj \
test_scheduler.obj test_introduce.obj test_hs.obj tinytest.obj
tinytest.obj: ..\ext\tinytest.c
@@ -30,8 +31,5 @@ test.exe: $(TEST_OBJECTS)
bench.exe: bench.obj
$(CC) $(CFLAGS) bench.obj $(LIBS) ..\common\*.lib /Fe$@
-test-child.exe: test-child.obj
- $(CC) $(CFLAGS) test-child.obj /Fe$@
-
clean:
- del *.obj *.lib test.exe bench.exe test-child.exe
+ del *.obj *.lib test.exe bench.exe
diff --git a/src/test/bench.c b/src/test/bench.c
index 06c616c3b0..7a8c04e802 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,16 +14,19 @@
#include "core/crypto/onion_tap.h"
#include "core/crypto/relay_crypto.h"
+#include "lib/intmath/weakrng.h"
+
#ifdef ENABLE_OPENSSL
#include <openssl/opensslv.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/obj_mac.h>
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
#include "core/or/circuitlist.h"
#include "app/config/config.h"
+#include "app/main/subsysmgr.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "core/crypto/onion_ntor.h"
@@ -38,6 +41,9 @@
#include "lib/crypt_ops/digestset.h"
#include "lib/crypt_ops/crypto_init.h"
+#include "feature/dirparse/microdesc_parse.h"
+#include "feature/nodelist/microdesc.h"
+
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
static uint64_t nanostart;
static inline uint64_t
@@ -332,6 +338,65 @@ bench_ed25519(void)
}
static void
+bench_rand_len(int len)
+{
+ const int N = 100000;
+ int i;
+ char *buf = tor_malloc(len);
+ uint64_t start,end;
+
+ start = perftime();
+ for (i = 0; i < N; ++i) {
+ crypto_rand(buf, len);
+ }
+ end = perftime();
+ printf("crypto_rand(%d): %f nsec.\n", len, NANOCOUNT(start,end,N));
+
+ crypto_fast_rng_t *fr = crypto_fast_rng_new();
+ start = perftime();
+ for (i = 0; i < N; ++i) {
+ crypto_fast_rng_getbytes(fr,(uint8_t*)buf,len);
+ }
+ end = perftime();
+ printf("crypto_fast_rng_getbytes(%d): %f nsec.\n", len,
+ NANOCOUNT(start,end,N));
+ crypto_fast_rng_free(fr);
+
+ if (len <= 32) {
+ start = perftime();
+ for (i = 0; i < N; ++i) {
+ crypto_strongest_rand((uint8_t*)buf, len);
+ }
+ end = perftime();
+ printf("crypto_strongest_rand(%d): %f nsec.\n", len,
+ NANOCOUNT(start,end,N));
+ }
+
+ if (len == 4) {
+ tor_weak_rng_t weak;
+ tor_init_weak_random(&weak, 1337);
+
+ start = perftime();
+ uint32_t t=0;
+ for (i = 0; i < N; ++i) {
+ t += tor_weak_random(&weak);
+ }
+ end = perftime();
+ printf("weak_rand(4): %f nsec.\n", NANOCOUNT(start,end,N));
+ }
+
+ tor_free(buf);
+}
+
+static void
+bench_rand(void)
+{
+ bench_rand_len(4);
+ bench_rand_len(16);
+ bench_rand_len(128);
+}
+
+static void
bench_cell_aes(void)
{
uint64_t start, end;
@@ -636,7 +701,42 @@ bench_ecdh_p224(void)
{
bench_ecdh_impl(NID_secp224r1, "P-224");
}
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
+
+static void
+bench_md_parse(void)
+{
+ uint64_t start, end;
+ const int N = 100000;
+ // selected arbitrarily
+ const char md_text[] =
+ "@last-listed 2018-12-14 18:14:14\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMHkZeXNDX/49JqM2BVLmh1Fnb5iMVnatvZZTLJyedqDLkbXZ1WKP5oh\n"
+ "7ec14dj/k3ntpwHD4s2o3Lb6nfagWbug4+F/rNJ7JuFru/PSyOvDyHGNAuegOXph\n"
+ "3gTGjdDpv/yPoiadGebbVe8E7n6hO+XxM2W/4dqheKimF0/s9B7HAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key QgF/EjqlNG1wRHLIop/nCekEH+ETGZSgYOhu26eiTF4=\n"
+ "family $00E9A86E7733240E60D8435A7BBD634A23894098 "
+ "$329BD7545DEEEBBDC8C4285F243916F248972102 "
+ "$69E06EBB2573A4F89330BDF8BC869794A3E10E4D "
+ "$DCA2A3FAE50B3729DAA15BC95FB21AF03389818B\n"
+ "p accept 53,80,443,5222-5223,25565\n"
+ "id ed25519 BzffzY99z6Q8KltcFlUTLWjNTBU7yKK+uQhyi1Ivb3A\n";
+
+ reset_perftime();
+ start = perftime();
+ for (int i = 0; i < N; ++i) {
+ smartlist_t *s = microdescs_parse_from_string(md_text, NULL, 1,
+ SAVED_IN_CACHE, NULL);
+ SMARTLIST_FOREACH(s, microdesc_t *, md, microdesc_free(md));
+ smartlist_free(s);
+ }
+
+ end = perftime();
+ printf("Microdesc parse: %f nsec\n", NANOCOUNT(start, end, N));
+}
typedef void (*bench_fn)(void);
@@ -656,6 +756,7 @@ static struct benchmark_t benchmarks[] = {
ENT(onion_TAP),
ENT(onion_ntor),
ENT(ed25519),
+ ENT(rand),
ENT(cell_aes),
ENT(cell_ops),
@@ -665,6 +766,8 @@ static struct benchmark_t benchmarks[] = {
ENT(ecdh_p256),
ENT(ecdh_p224),
#endif
+
+ ENT(md_parse),
{NULL,NULL,0}
};
@@ -690,9 +793,10 @@ main(int argc, const char **argv)
char *errmsg;
or_options_t *options;
- tor_threads_init();
+ subsystems_init_upto(SUBSYS_LEVEL_LIBS);
+ flush_log_messages_from_startup();
+
tor_compress_init();
- init_logging(1);
if (argc == 4 && !strcmp(argv[1], "diff")) {
const int N = 200;
@@ -702,11 +806,13 @@ main(int argc, const char **argv)
perror("X");
return 1;
}
+ size_t f1len = strlen(f1);
+ size_t f2len = strlen(f2);
for (i = 0; i < N; ++i) {
- char *diff = consensus_diff_generate(f1, f2);
+ char *diff = consensus_diff_generate(f1, f1len, f2, f2len);
tor_free(diff);
}
- char *diff = consensus_diff_generate(f1, f2);
+ char *diff = consensus_diff_generate(f1, f1len, f2, f2len);
printf("%s", diff);
tor_free(f1);
tor_free(f2);
@@ -737,7 +843,6 @@ main(int argc, const char **argv)
init_protocol_warning_severity_level();
options = options_new();
- init_logging(1);
options->command = CMD_RUN_UNITTESTS;
options->DataDirectory = tor_strdup("");
options->KeyDirectory = tor_strdup("");
diff --git a/src/test/bt_test.py b/src/test/bt_test.py
index f9ca79efde..d728f13596 100755
--- a/src/test/bt_test.py
+++ b/src/test/bt_test.py
@@ -15,7 +15,11 @@ OK
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
diff --git a/src/test/conf_examples/badnick_1/error b/src/test/conf_examples/badnick_1/error
new file mode 100644
index 0000000000..3e92ddc832
--- /dev/null
+++ b/src/test/conf_examples/badnick_1/error
@@ -0,0 +1 @@
+nicknames must be between 1 and 19 characters inclusive
diff --git a/src/test/conf_examples/badnick_1/expected_log_no_dirauth_relay b/src/test/conf_examples/badnick_1/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..9190a3326b
--- /dev/null
+++ b/src/test/conf_examples/badnick_1/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*badnick_1[./]*torrc
diff --git a/src/test/conf_examples/badnick_1/expected_no_dirauth_relay b/src/test/conf_examples/badnick_1/expected_no_dirauth_relay
new file mode 100644
index 0000000000..b00be15c2e
--- /dev/null
+++ b/src/test/conf_examples/badnick_1/expected_no_dirauth_relay
@@ -0,0 +1 @@
+Nickname TooManyCharactersInThisNickname
diff --git a/src/test/conf_examples/badnick_1/torrc b/src/test/conf_examples/badnick_1/torrc
new file mode 100644
index 0000000000..087e3f2ff1
--- /dev/null
+++ b/src/test/conf_examples/badnick_1/torrc
@@ -0,0 +1,4 @@
+# This nickname is too long; we won't accept it.
+# (Unless the relay module is disabled, because Nickname is a
+# relay-only option. We'll ignore all relay-only options in #32395.)
+Nickname TooManyCharactersInThisNickname
diff --git a/src/test/conf_examples/badnick_2/error b/src/test/conf_examples/badnick_2/error
new file mode 100644
index 0000000000..ceac99f012
--- /dev/null
+++ b/src/test/conf_examples/badnick_2/error
@@ -0,0 +1 @@
+must contain only the characters \[a-zA-Z0-9\]
diff --git a/src/test/conf_examples/badnick_2/expected_log_no_dirauth_relay b/src/test/conf_examples/badnick_2/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..a15c7b02cb
--- /dev/null
+++ b/src/test/conf_examples/badnick_2/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*badnick_2[./]*torrc
diff --git a/src/test/conf_examples/badnick_2/expected_no_dirauth_relay b/src/test/conf_examples/badnick_2/expected_no_dirauth_relay
new file mode 100644
index 0000000000..08dcdc33a9
--- /dev/null
+++ b/src/test/conf_examples/badnick_2/expected_no_dirauth_relay
@@ -0,0 +1 @@
+Nickname has a space
diff --git a/src/test/conf_examples/badnick_2/torrc b/src/test/conf_examples/badnick_2/torrc
new file mode 100644
index 0000000000..51a5f96c00
--- /dev/null
+++ b/src/test/conf_examples/badnick_2/torrc
@@ -0,0 +1,4 @@
+# this nickname has spaces in it and won't work.
+# (Unless the relay module is disabled, because Nickname is a
+# relay-only option. We'll ignore all relay-only options in #32395.)
+Nickname has a space
diff --git a/src/test/conf_examples/bridgeauth_1/error_no_dirauth b/src/test/conf_examples/bridgeauth_1/error_no_dirauth
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/bridgeauth_1/error_no_dirauth
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/bridgeauth_1/error_no_dirauth_relay b/src/test/conf_examples/bridgeauth_1/error_no_dirauth_relay
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/bridgeauth_1/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/bridgeauth_1/expected b/src/test/conf_examples/bridgeauth_1/expected
new file mode 100644
index 0000000000..d43aaf2c8b
--- /dev/null
+++ b/src/test/conf_examples/bridgeauth_1/expected
@@ -0,0 +1,7 @@
+Address 198.51.100.123
+AuthoritativeDirectory 1
+BridgeAuthoritativeDir 1
+ContactInfo tor_parse_test@example.com
+DirPort 80
+Nickname Unnamed
+ORPort 443
diff --git a/src/test/conf_examples/bridgeauth_1/expected_log b/src/test/conf_examples/bridgeauth_1/expected_log
new file mode 100644
index 0000000000..cabe9d3f89
--- /dev/null
+++ b/src/test/conf_examples/bridgeauth_1/expected_log
@@ -0,0 +1 @@
+Read configuration file .*bridgeauth_1[./]*torrc
diff --git a/src/test/conf_examples/bridgeauth_1/torrc b/src/test/conf_examples/bridgeauth_1/torrc
new file mode 100644
index 0000000000..740bc6c2eb
--- /dev/null
+++ b/src/test/conf_examples/bridgeauth_1/torrc
@@ -0,0 +1,8 @@
+AuthoritativeDirectory 1
+BridgeAuthoritativeDir 1
+
+ContactInfo tor_parse_test@example.com
+
+Address 198.51.100.123
+ORPort 443
+DirPort 80
diff --git a/src/test/conf_examples/bug_31495_1/expected b/src/test/conf_examples/bug_31495_1/expected
new file mode 100644
index 0000000000..246347b668
--- /dev/null
+++ b/src/test/conf_examples/bug_31495_1/expected
@@ -0,0 +1,2 @@
+Bridge 127.0.0.1:9050
+UseBridges 1
diff --git a/src/test/conf_examples/bug_31495_1/expected_log b/src/test/conf_examples/bug_31495_1/expected_log
new file mode 100644
index 0000000000..a4b98345d6
--- /dev/null
+++ b/src/test/conf_examples/bug_31495_1/expected_log
@@ -0,0 +1 @@
+Configuration was valid \ No newline at end of file
diff --git a/src/test/conf_examples/bug_31495_1/torrc b/src/test/conf_examples/bug_31495_1/torrc
new file mode 100644
index 0000000000..ed6cccab3f
--- /dev/null
+++ b/src/test/conf_examples/bug_31495_1/torrc
@@ -0,0 +1,2 @@
+UseBridges 1
+Bridge 127.0.0.1:9050 \ No newline at end of file
diff --git a/src/test/conf_examples/bug_31495_2/error b/src/test/conf_examples/bug_31495_2/error
new file mode 100644
index 0000000000..1417806c60
--- /dev/null
+++ b/src/test/conf_examples/bug_31495_2/error
@@ -0,0 +1 @@
+Failed to parse/validate config: You cannot set both UseBridges and EntryNodes. \ No newline at end of file
diff --git a/src/test/conf_examples/bug_31495_2/torrc b/src/test/conf_examples/bug_31495_2/torrc
new file mode 100644
index 0000000000..f629fff673
--- /dev/null
+++ b/src/test/conf_examples/bug_31495_2/torrc
@@ -0,0 +1,3 @@
+UseBridges 1
+Bridge 127.0.0.1:9050
+EntryNodes 127.0.0.1 \ No newline at end of file
diff --git a/src/test/conf_examples/bug_31495_3/cmdline b/src/test/conf_examples/bug_31495_3/cmdline
new file mode 100644
index 0000000000..478c1abe74
--- /dev/null
+++ b/src/test/conf_examples/bug_31495_3/cmdline
@@ -0,0 +1 @@
+/EntryNodes \ No newline at end of file
diff --git a/src/test/conf_examples/bug_31495_3/expected b/src/test/conf_examples/bug_31495_3/expected
new file mode 100644
index 0000000000..246347b668
--- /dev/null
+++ b/src/test/conf_examples/bug_31495_3/expected
@@ -0,0 +1,2 @@
+Bridge 127.0.0.1:9050
+UseBridges 1
diff --git a/src/test/conf_examples/bug_31495_3/expected_log b/src/test/conf_examples/bug_31495_3/expected_log
new file mode 100644
index 0000000000..a4b98345d6
--- /dev/null
+++ b/src/test/conf_examples/bug_31495_3/expected_log
@@ -0,0 +1 @@
+Configuration was valid \ No newline at end of file
diff --git a/src/test/conf_examples/bug_31495_3/torrc b/src/test/conf_examples/bug_31495_3/torrc
new file mode 100644
index 0000000000..f629fff673
--- /dev/null
+++ b/src/test/conf_examples/bug_31495_3/torrc
@@ -0,0 +1,3 @@
+UseBridges 1
+Bridge 127.0.0.1:9050
+EntryNodes 127.0.0.1 \ No newline at end of file
diff --git a/src/test/conf_examples/contactinfo_notutf8/error b/src/test/conf_examples/contactinfo_notutf8/error
new file mode 100644
index 0000000000..6d165152ce
--- /dev/null
+++ b/src/test/conf_examples/contactinfo_notutf8/error
@@ -0,0 +1 @@
+ContactInfo config option must be UTF-8
diff --git a/src/test/conf_examples/contactinfo_notutf8/expected_log_no_dirauth_relay b/src/test/conf_examples/contactinfo_notutf8/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..caa07aca40
--- /dev/null
+++ b/src/test/conf_examples/contactinfo_notutf8/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*contactinfo_notutf8[./]*torrc
diff --git a/src/test/conf_examples/contactinfo_notutf8/expected_no_dirauth_relay b/src/test/conf_examples/contactinfo_notutf8/expected_no_dirauth_relay
new file mode 100644
index 0000000000..cc8bd7b8e3
--- /dev/null
+++ b/src/test/conf_examples/contactinfo_notutf8/expected_no_dirauth_relay
@@ -0,0 +1 @@
+ContactInfo "\304\353\304\353\304\353@example.com"
diff --git a/src/test/conf_examples/contactinfo_notutf8/torrc b/src/test/conf_examples/contactinfo_notutf8/torrc
new file mode 100644
index 0000000000..0176a56a97
--- /dev/null
+++ b/src/test/conf_examples/contactinfo_notutf8/torrc
@@ -0,0 +1,5 @@
+# We only accept ContactInfo in UTF-8 (or 7-bit ASCII)
+# (Unless the relay module is disabled, because ContactInfo is a
+# relay-only option. We'll ignore all relay-only options in #32395.
+# But at the moment, tor canonicalises and quotes the string.)
+ContactInfo ÄëÄëÄë@example.com
diff --git a/src/test/conf_examples/controlsock/error b/src/test/conf_examples/controlsock/error
new file mode 100644
index 0000000000..8fbea37894
--- /dev/null
+++ b/src/test/conf_examples/controlsock/error
@@ -0,0 +1 @@
+not supported on this OS\|without setting a ControlSocket
diff --git a/src/test/conf_examples/controlsock/torrc b/src/test/conf_examples/controlsock/torrc
new file mode 100644
index 0000000000..dd3cb7ede5
--- /dev/null
+++ b/src/test/conf_examples/controlsock/torrc
@@ -0,0 +1 @@
+ControlSocketsGroupWritable 1
diff --git a/src/test/conf_examples/crypto_accel/expected b/src/test/conf_examples/crypto_accel/expected
new file mode 100644
index 0000000000..ea80ca19dc
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel/expected
@@ -0,0 +1,2 @@
+AccelName nonexistent_chartreuse_accelerator
+HardwareAccel 1
diff --git a/src/test/conf_examples/crypto_accel/expected_log b/src/test/conf_examples/crypto_accel/expected_log
new file mode 100644
index 0000000000..7fab0c8dad
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel/expected_log
@@ -0,0 +1 @@
+Unable to load dynamic OpenSSL engine "nonexistent_chartreuse_accelerator"
diff --git a/src/test/conf_examples/crypto_accel/expected_log_nss b/src/test/conf_examples/crypto_accel/expected_log_nss
new file mode 100644
index 0000000000..bcbfa2cf6b
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel/expected_log_nss
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc
diff --git a/src/test/conf_examples/crypto_accel/expected_nss b/src/test/conf_examples/crypto_accel/expected_nss
new file mode 100644
index 0000000000..ea80ca19dc
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel/expected_nss
@@ -0,0 +1,2 @@
+AccelName nonexistent_chartreuse_accelerator
+HardwareAccel 1
diff --git a/src/test/conf_examples/crypto_accel/torrc b/src/test/conf_examples/crypto_accel/torrc
new file mode 100644
index 0000000000..9ca18903b7
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel/torrc
@@ -0,0 +1,3 @@
+
+AccelName nonexistent_chartreuse_accelerator
+HardwareAccel 1
diff --git a/src/test/conf_examples/crypto_accel_req/error b/src/test/conf_examples/crypto_accel_req/error
new file mode 100644
index 0000000000..e12e002915
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel_req/error
@@ -0,0 +1 @@
+Unable to load required dynamic OpenSSL engine "nonexistent_chartreuse_accelerator"
diff --git a/src/test/conf_examples/crypto_accel_req/expected_log_nss b/src/test/conf_examples/crypto_accel_req/expected_log_nss
new file mode 100644
index 0000000000..bcbfa2cf6b
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel_req/expected_log_nss
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc
diff --git a/src/test/conf_examples/crypto_accel_req/expected_nss b/src/test/conf_examples/crypto_accel_req/expected_nss
new file mode 100644
index 0000000000..f3e172f640
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel_req/expected_nss
@@ -0,0 +1,2 @@
+AccelName !nonexistent_chartreuse_accelerator
+HardwareAccel 1
diff --git a/src/test/conf_examples/crypto_accel_req/torrc b/src/test/conf_examples/crypto_accel_req/torrc
new file mode 100644
index 0000000000..981d9116fc
--- /dev/null
+++ b/src/test/conf_examples/crypto_accel_req/torrc
@@ -0,0 +1,3 @@
+
+AccelName !nonexistent_chartreuse_accelerator
+HardwareAccel 1
diff --git a/src/test/conf_examples/dirauth_1/error_no_dirauth b/src/test/conf_examples/dirauth_1/error_no_dirauth
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_1/error_no_dirauth
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/dirauth_1/error_no_dirauth_relay b/src/test/conf_examples/dirauth_1/error_no_dirauth_relay
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_1/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/dirauth_1/expected b/src/test/conf_examples/dirauth_1/expected
new file mode 100644
index 0000000000..901f7d947f
--- /dev/null
+++ b/src/test/conf_examples/dirauth_1/expected
@@ -0,0 +1,8 @@
+Address 192.0.2.1
+AuthoritativeDirectory 1
+ContactInfo tor_parse_test@example.net
+DirPort 9030
+DownloadExtraInfo 1
+Nickname Unnamed
+ORPort 9001
+V3AuthoritativeDirectory 1
diff --git a/src/test/conf_examples/dirauth_1/expected_log b/src/test/conf_examples/dirauth_1/expected_log
new file mode 100644
index 0000000000..b788be2e33
--- /dev/null
+++ b/src/test/conf_examples/dirauth_1/expected_log
@@ -0,0 +1 @@
+Read configuration file .*dirauth_1[./]*torrc
diff --git a/src/test/conf_examples/dirauth_1/torrc b/src/test/conf_examples/dirauth_1/torrc
new file mode 100644
index 0000000000..b870e6e8e0
--- /dev/null
+++ b/src/test/conf_examples/dirauth_1/torrc
@@ -0,0 +1,8 @@
+AuthoritativeDirectory 1
+V3AuthoritativeDirectory 1
+
+ContactInfo tor_parse_test@example.net
+
+Address 192.0.2.1
+ORPort 9001
+DirPort 9030
diff --git a/src/test/conf_examples/dirauth_2/expected b/src/test/conf_examples/dirauth_2/expected
new file mode 100644
index 0000000000..19ab024ed3
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected
@@ -0,0 +1 @@
+AuthDirMaxServersPerAddr 8
diff --git a/src/test/conf_examples/dirauth_2/expected_log b/src/test/conf_examples/dirauth_2/expected_log
new file mode 100644
index 0000000000..88611fee9d
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected_log
@@ -0,0 +1 @@
+Read configuration file
diff --git a/src/test/conf_examples/dirauth_2/expected_log_no_dirauth b/src/test/conf_examples/dirauth_2/expected_log_no_dirauth
new file mode 100644
index 0000000000..01110c5d8c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected_log_no_dirauth
@@ -0,0 +1 @@
+This copy of Tor was built without support for the option "AuthDirMaxServersPerAddr". Skipping. \ No newline at end of file
diff --git a/src/test/conf_examples/dirauth_2/expected_log_no_dirauth_relay b/src/test/conf_examples/dirauth_2/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..01110c5d8c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+This copy of Tor was built without support for the option "AuthDirMaxServersPerAddr". Skipping. \ No newline at end of file
diff --git a/src/test/conf_examples/dirauth_2/expected_no_dirauth b/src/test/conf_examples/dirauth_2/expected_no_dirauth
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected_no_dirauth
diff --git a/src/test/conf_examples/dirauth_2/expected_no_dirauth_relay b/src/test/conf_examples/dirauth_2/expected_no_dirauth_relay
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/expected_no_dirauth_relay
diff --git a/src/test/conf_examples/dirauth_2/torrc b/src/test/conf_examples/dirauth_2/torrc
new file mode 100644
index 0000000000..bd1cdbc8b9
--- /dev/null
+++ b/src/test/conf_examples/dirauth_2/torrc
@@ -0,0 +1,5 @@
+#
+# This will get accepted if the module is enabled, and ignored if the module
+# is disabled.
+#
+AuthDirMaxServersPerAddr 8
diff --git a/src/test/conf_examples/dirauth_3/error_no_dirauth b/src/test/conf_examples/dirauth_3/error_no_dirauth
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/error_no_dirauth
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/dirauth_3/error_no_dirauth_relay b/src/test/conf_examples/dirauth_3/error_no_dirauth_relay
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/dirauth_3/expected b/src/test/conf_examples/dirauth_3/expected
new file mode 100644
index 0000000000..23eac3a5f8
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/expected
@@ -0,0 +1,9 @@
+Address 192.0.2.1
+AuthoritativeDirectory 1
+ContactInfo tor_parse_test@example.net
+DirPort 192.0.2.1:2
+DownloadExtraInfo 1
+Nickname Unnamed
+ORPort 192.0.2.1:1
+ORPort [2001:DB8::1]:3
+V3AuthoritativeDirectory 1
diff --git a/src/test/conf_examples/dirauth_3/expected_log b/src/test/conf_examples/dirauth_3/expected_log
new file mode 100644
index 0000000000..3127c9b125
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/expected_log
@@ -0,0 +1 @@
+Read configuration file .*dirauth_3[./]*torrc
diff --git a/src/test/conf_examples/dirauth_3/torrc b/src/test/conf_examples/dirauth_3/torrc
new file mode 100644
index 0000000000..9663a9bc0c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/torrc
@@ -0,0 +1,13 @@
+# Authority with IPv6 address
+
+AuthoritativeDirectory 1
+V3AuthoritativeDirectory 1
+
+ContactInfo tor_parse_test@example.net
+
+Address 192.0.2.1
+
+ORPort 192.0.2.1:1
+DirPort 192.0.2.1:2
+
+ORPort [2001:DB8::1]:3
diff --git a/src/test/conf_examples/empty_1/expected b/src/test/conf_examples/empty_1/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_1/expected
diff --git a/src/test/conf_examples/empty_1/expected_log b/src/test/conf_examples/empty_1/expected_log
new file mode 100644
index 0000000000..4c6b00069f
--- /dev/null
+++ b/src/test/conf_examples/empty_1/expected_log
@@ -0,0 +1 @@
+Read configuration file .*empty_1[./]*torrc
diff --git a/src/test/conf_examples/empty_1/torrc b/src/test/conf_examples/empty_1/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_1/torrc
diff --git a/src/test/conf_examples/empty_2/cmdline b/src/test/conf_examples/empty_2/cmdline
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_2/cmdline
diff --git a/src/test/conf_examples/empty_2/expected b/src/test/conf_examples/empty_2/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_2/expected
diff --git a/src/test/conf_examples/empty_2/expected_log b/src/test/conf_examples/empty_2/expected_log
new file mode 100644
index 0000000000..9c846a03f3
--- /dev/null
+++ b/src/test/conf_examples/empty_2/expected_log
@@ -0,0 +1 @@
+Read configuration file .*empty_2[./]*torrc\.defaults
diff --git a/src/test/conf_examples/empty_2/torrc b/src/test/conf_examples/empty_2/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_2/torrc
diff --git a/src/test/conf_examples/empty_2/torrc.defaults b/src/test/conf_examples/empty_2/torrc.defaults
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_2/torrc.defaults
diff --git a/src/test/conf_examples/empty_3/expected b/src/test/conf_examples/empty_3/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_3/expected
diff --git a/src/test/conf_examples/empty_3/expected_log b/src/test/conf_examples/empty_3/expected_log
new file mode 100644
index 0000000000..e3f2365893
--- /dev/null
+++ b/src/test/conf_examples/empty_3/expected_log
@@ -0,0 +1 @@
+Processing configuration path \".*included\" at recursion level 1\.
diff --git a/src/test/conf_examples/empty_3/included/empty b/src/test/conf_examples/empty_3/included/empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/empty_3/included/empty
diff --git a/src/test/conf_examples/empty_3/torrc b/src/test/conf_examples/empty_3/torrc
new file mode 100644
index 0000000000..049b438903
--- /dev/null
+++ b/src/test/conf_examples/empty_3/torrc
@@ -0,0 +1 @@
+%include "included"
diff --git a/src/test/conf_examples/empty_4/error b/src/test/conf_examples/empty_4/error
new file mode 100644
index 0000000000..e6c2f7d885
--- /dev/null
+++ b/src/test/conf_examples/empty_4/error
@@ -0,0 +1 @@
+Unable to open configuration file \ No newline at end of file
diff --git a/src/test/conf_examples/example_1/expected b/src/test/conf_examples/example_1/expected
new file mode 100644
index 0000000000..9d6688a565
--- /dev/null
+++ b/src/test/conf_examples/example_1/expected
@@ -0,0 +1,2 @@
+ContactInfo tor_tellini@example.com
+SocksPort 80
diff --git a/src/test/conf_examples/example_1/expected_log b/src/test/conf_examples/example_1/expected_log
new file mode 100644
index 0000000000..8f83eec988
--- /dev/null
+++ b/src/test/conf_examples/example_1/expected_log
@@ -0,0 +1 @@
+Read configuration file .*example_1[./]*torrc
diff --git a/src/test/conf_examples/example_1/torrc b/src/test/conf_examples/example_1/torrc
new file mode 100644
index 0000000000..bff7fa0aa2
--- /dev/null
+++ b/src/test/conf_examples/example_1/torrc
@@ -0,0 +1,5 @@
+
+# Here is a simple example torrc.
+ SocksPort 80
+
+ContactInfo "tor_tellini@example.com"
diff --git a/src/test/conf_examples/example_2/error b/src/test/conf_examples/example_2/error
new file mode 100644
index 0000000000..ce18b68db4
--- /dev/null
+++ b/src/test/conf_examples/example_2/error
@@ -0,0 +1 @@
+Unknown option 'JumpingJellyjars'
diff --git a/src/test/conf_examples/example_2/torrc b/src/test/conf_examples/example_2/torrc
new file mode 100644
index 0000000000..8ec8133b24
--- /dev/null
+++ b/src/test/conf_examples/example_2/torrc
@@ -0,0 +1 @@
+JumpingJellyjars 1
diff --git a/src/test/conf_examples/example_3/cmdline b/src/test/conf_examples/example_3/cmdline
new file mode 100644
index 0000000000..5b2fadcebb
--- /dev/null
+++ b/src/test/conf_examples/example_3/cmdline
@@ -0,0 +1 @@
+--socksport 99
diff --git a/src/test/conf_examples/example_3/expected b/src/test/conf_examples/example_3/expected
new file mode 100644
index 0000000000..867fb8bcc8
--- /dev/null
+++ b/src/test/conf_examples/example_3/expected
@@ -0,0 +1 @@
+SocksPort 99
diff --git a/src/test/conf_examples/example_3/expected_log b/src/test/conf_examples/example_3/expected_log
new file mode 100644
index 0000000000..807f9c2fc8
--- /dev/null
+++ b/src/test/conf_examples/example_3/expected_log
@@ -0,0 +1 @@
+Read configuration file .*example_3[./]*torrc
diff --git a/src/test/conf_examples/example_3/torrc b/src/test/conf_examples/example_3/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/example_3/torrc
diff --git a/src/test/conf_examples/include_1/error_no_dirauth_relay b/src/test/conf_examples/include_1/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/include_1/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/include_1/expected b/src/test/conf_examples/include_1/expected
new file mode 100644
index 0000000000..4bbf52ce9f
--- /dev/null
+++ b/src/test/conf_examples/include_1/expected
@@ -0,0 +1,3 @@
+ContactInfo includefile@example.com
+Nickname nested
+ORPort 8008
diff --git a/src/test/conf_examples/include_1/expected_log b/src/test/conf_examples/include_1/expected_log
new file mode 100644
index 0000000000..0791a494d2
--- /dev/null
+++ b/src/test/conf_examples/include_1/expected_log
@@ -0,0 +1 @@
+Processing configuration path \".*nested\.inc\" at recursion level 2\.
diff --git a/src/test/conf_examples/include_1/included.inc b/src/test/conf_examples/include_1/included.inc
new file mode 100644
index 0000000000..8d1834345d
--- /dev/null
+++ b/src/test/conf_examples/include_1/included.inc
@@ -0,0 +1,4 @@
+
+ContactInfo includefile@example.com
+
+%include "nested.inc" \ No newline at end of file
diff --git a/src/test/conf_examples/include_1/nested.inc b/src/test/conf_examples/include_1/nested.inc
new file mode 100644
index 0000000000..789b044a2b
--- /dev/null
+++ b/src/test/conf_examples/include_1/nested.inc
@@ -0,0 +1,2 @@
+
+Nickname nested \ No newline at end of file
diff --git a/src/test/conf_examples/include_1/torrc b/src/test/conf_examples/include_1/torrc
new file mode 100644
index 0000000000..2ed4074f6e
--- /dev/null
+++ b/src/test/conf_examples/include_1/torrc
@@ -0,0 +1,4 @@
+
+%include "included.inc"
+
+ORPort 8008
diff --git a/src/test/conf_examples/include_bug_31408/error_no_dirauth_relay b/src/test/conf_examples/include_bug_31408/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/include_bug_31408/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/include_bug_31408/expected b/src/test/conf_examples/include_bug_31408/expected
new file mode 100644
index 0000000000..2e822f1a78
--- /dev/null
+++ b/src/test/conf_examples/include_bug_31408/expected
@@ -0,0 +1,2 @@
+Nickname test31408
+ORPort 31408
diff --git a/src/test/conf_examples/include_bug_31408/expected_log b/src/test/conf_examples/include_bug_31408/expected_log
new file mode 100644
index 0000000000..e3f2365893
--- /dev/null
+++ b/src/test/conf_examples/include_bug_31408/expected_log
@@ -0,0 +1 @@
+Processing configuration path \".*included\" at recursion level 1\.
diff --git a/src/test/conf_examples/include_bug_31408/included/01_nickname.inc b/src/test/conf_examples/include_bug_31408/included/01_nickname.inc
new file mode 100644
index 0000000000..508dd89a35
--- /dev/null
+++ b/src/test/conf_examples/include_bug_31408/included/01_nickname.inc
@@ -0,0 +1 @@
+Nickname test31408
diff --git a/src/test/conf_examples/include_bug_31408/included/02_no_configs.inc b/src/test/conf_examples/include_bug_31408/included/02_no_configs.inc
new file mode 100644
index 0000000000..140e927f19
--- /dev/null
+++ b/src/test/conf_examples/include_bug_31408/included/02_no_configs.inc
@@ -0,0 +1,3 @@
+# Bug 31048 is triggered when the last file in a config directory:
+# * contains no configuration options,
+# * but is non-empty: that is, it contains comments or whitespace.
diff --git a/src/test/conf_examples/include_bug_31408/torrc b/src/test/conf_examples/include_bug_31408/torrc
new file mode 100644
index 0000000000..a42685e93c
--- /dev/null
+++ b/src/test/conf_examples/include_bug_31408/torrc
@@ -0,0 +1,2 @@
+%include "included"
+ORPort 31408
diff --git a/src/test/conf_examples/large_1/error_no_dirauth_relay b/src/test/conf_examples/large_1/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/large_1/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/large_1/expected b/src/test/conf_examples/large_1/expected
new file mode 100644
index 0000000000..fcd19db3df
--- /dev/null
+++ b/src/test/conf_examples/large_1/expected
@@ -0,0 +1,156 @@
+AccountingMax 10737418240
+AccountingRule sum
+AccountingStart day 05:15
+Address 128.66.8.8
+AllowNonRFC953Hostnames 1
+AutomapHostsOnResolve 1
+AutomapHostsSuffixes .onions
+AvoidDiskWrites 1
+BandwidthBurst 2147483647
+BandwidthRate 1610612736
+Bridge 128.66.1.10:80
+CacheDirectory /this-is-a-cache
+CellStatistics 1
+CircuitBuildTimeout 200
+CircuitsAvailableTimeout 10
+CircuitStreamTimeout 20
+ClientOnly 1
+ClientPreferIPv6DirPort 1
+ClientPreferIPv6ORPort 1
+ClientRejectInternalAddresses 0
+ClientUseIPv4 0
+ClientUseIPv6 1
+ConnDirectionStatistics 1
+ConnectionPadding 1
+ConnLimit 64
+ConsensusParams wombat=7
+ConstrainedSockets 1
+ConstrainedSockSize 10240
+ContactInfo long_config@example.com
+ControlPortFileGroupReadable 1
+ControlPort 9058
+CookieAuthentication 1
+CookieAuthFile /control/cookie
+CookieAuthFileGroupReadable 1
+CountPrivateBandwidth 1
+DataDirectory /data/dir
+DirAllowPrivateAddresses 1
+DirPolicy reject 128.66.1.1/32, accept *:*
+DirPortFrontPage /dirport/frontpage
+DirPort 99
+DirReqStatistics 0
+DisableDebuggerAttachment 0
+DisableNetwork 1
+DisableOOSCheck 0
+DNSPort 53535
+DormantCanceledByStartup 1
+DormantClientTimeout 1260
+DormantOnFirstStartup 1
+DormantTimeoutDisabledByIdleStreams 0
+DoSCircuitCreationBurst 1000
+DoSCircuitCreationDefenseTimePeriod 300
+DoSCircuitCreationDefenseType 2
+DoSCircuitCreationEnabled 1
+DoSCircuitCreationMinConnections 10
+DoSCircuitCreationRate 100
+DoSConnectionDefenseType 2
+DoSConnectionEnabled 1
+DoSConnectionMaxConcurrentCount 6
+DoSRefuseSingleHopClientRendezvous 0
+DownloadExtraInfo 1
+EnforceDistinctSubnets 0
+EntryNodes potrzebie,triffid,cromulent
+EntryStatistics 1
+ExcludeExitNodes blaznort,kriffid,zeppelin
+ExcludeNodes 128.66.7.6
+ExitNodes 128.66.7.7,128.66.128.0/17,exitexit
+ExitPolicy accept *:80,reject *:*
+ExitPolicyRejectLocalInterfaces 1
+ExitPolicyRejectPrivate 0
+ExitPortStatistics 1
+ExitRelay 1
+ExtendAllowPrivateAddresses 1
+ExtendByEd25519ID 1
+ExtORPortCookieAuthFile /foobar
+ExtORPort 99
+FascistFirewall 1
+FetchDirInfoEarly 1
+FetchDirInfoExtraEarly 1
+FetchUselessDescriptors 1
+FirewallPorts 80,443,999
+GeoIPExcludeUnknown 1
+GeoIPFile /geoip
+GuardfractionFile /gff
+GuardLifetime 691200
+HeartbeatPeriod 2700
+IPv6Exit 1
+KeepalivePeriod 540
+KeyDirectory /keyz
+KISTSchedRunInterval 1
+Log notice file /logfile
+Log info file /logfile-verbose
+LogTimeGranularity 60000
+LongLivedPorts 9090
+MainloopStats 1
+MapAddress www.example.com:10.0.0.6
+MaxAdvertisedBandwidth 100
+MaxCircuitDirtiness 3600
+MaxClientCircuitsPending 127
+MaxConsensusAgeForDiffs 2629728
+MaxMemInQueues 314572800
+MaxOnionQueueDelay 60000
+MaxUnparseableDescSizeToLog 1048576
+MiddleNodes grommit,truffle,parcheesi
+MyFamily $ffffffffffffffffffffffffffffffffffffffff
+NewCircuitPeriod 7200
+Nickname nickname
+NodeFamily $ffffffffffffffffffffffffffffffffffffffff,$dddddddddddddddddddddddddddddddddddddddd
+NumCPUs 3
+NumDirectoryGuards 4
+NumEntryGuards 5
+NumPrimaryGuards 8
+OfflineMasterKey 1
+ORPort 2222
+OutboundBindAddress 10.0.0.7
+OutboundBindAddressExit 10.0.0.8
+OutboundBindAddressOR 10.0.0.9
+PerConnBWBurst 10485760
+PerConnBWRate 102400
+PidFile /piddy
+ProtocolWarnings 1
+PublishHidServDescriptors 0
+PublishServerDescriptor 0
+ReachableAddresses 0.0.0.0, *:*
+ReachableDirAddresses 128.0.0.0/1
+ReachableORAddresses 128.0.0.0/8
+RejectPlaintextPorts 23
+RelayBandwidthBurst 10000
+RelayBandwidthRate 1000
+RendPostPeriod 600
+RephistTrackTime 600
+SafeLogging 0
+Schedulers Vanilla,KISTLite,Kist
+ShutdownWaitLength 10
+SigningKeyLifetime 4838400
+Socks5Proxy 128.66.99.99:99
+Socks5ProxyPassword flynn
+Socks5ProxyUsername spaceparanoids
+SocksPolicy accept 127.0.0.0/24, reject *:*
+SocksPort 9099
+SocksTimeout 600
+SSLKeyLifetime 86400
+StrictNodes 1
+SyslogIdentityTag tortor
+TestSocks 1
+TokenBucketRefillInterval 1000
+TrackHostExits www.example.com
+TrackHostExitsExpire 3600
+TruncateLogFile 1
+UnixSocksGroupWritable 1
+UpdateBridgesFromAuthority 1
+UseDefaultFallbackDirs 0
+UseGuardFraction 1
+UseMicrodescriptors 0
+VirtualAddrNetworkIPv4 18.66.0.0/16
+VirtualAddrNetworkIPv6 [ff00::]/16
+WarnPlaintextPorts 7,11,23,1001
diff --git a/src/test/conf_examples/large_1/expected_log b/src/test/conf_examples/large_1/expected_log
new file mode 100644
index 0000000000..21248bb5e4
--- /dev/null
+++ b/src/test/conf_examples/large_1/expected_log
@@ -0,0 +1 @@
+Your log may contain sensitive information
diff --git a/src/test/conf_examples/large_1/expected_log_no_dirauth b/src/test/conf_examples/large_1/expected_log_no_dirauth
new file mode 100644
index 0000000000..0b74de4e40
--- /dev/null
+++ b/src/test/conf_examples/large_1/expected_log_no_dirauth
@@ -0,0 +1 @@
+This copy of Tor was built without support for the option "ConsensusParams". Skipping.
diff --git a/src/test/conf_examples/large_1/expected_no_dirauth b/src/test/conf_examples/large_1/expected_no_dirauth
new file mode 100644
index 0000000000..4a19bc546c
--- /dev/null
+++ b/src/test/conf_examples/large_1/expected_no_dirauth
@@ -0,0 +1,155 @@
+AccountingMax 10737418240
+AccountingRule sum
+AccountingStart day 05:15
+Address 128.66.8.8
+AllowNonRFC953Hostnames 1
+AutomapHostsOnResolve 1
+AutomapHostsSuffixes .onions
+AvoidDiskWrites 1
+BandwidthBurst 2147483647
+BandwidthRate 1610612736
+Bridge 128.66.1.10:80
+CacheDirectory /this-is-a-cache
+CellStatistics 1
+CircuitBuildTimeout 200
+CircuitsAvailableTimeout 10
+CircuitStreamTimeout 20
+ClientOnly 1
+ClientPreferIPv6DirPort 1
+ClientPreferIPv6ORPort 1
+ClientRejectInternalAddresses 0
+ClientUseIPv4 0
+ClientUseIPv6 1
+ConnDirectionStatistics 1
+ConnectionPadding 1
+ConnLimit 64
+ConstrainedSockets 1
+ConstrainedSockSize 10240
+ContactInfo long_config@example.com
+ControlPortFileGroupReadable 1
+ControlPort 9058
+CookieAuthentication 1
+CookieAuthFile /control/cookie
+CookieAuthFileGroupReadable 1
+CountPrivateBandwidth 1
+DataDirectory /data/dir
+DirAllowPrivateAddresses 1
+DirPolicy reject 128.66.1.1/32, accept *:*
+DirPortFrontPage /dirport/frontpage
+DirPort 99
+DirReqStatistics 0
+DisableDebuggerAttachment 0
+DisableNetwork 1
+DisableOOSCheck 0
+DNSPort 53535
+DormantCanceledByStartup 1
+DormantClientTimeout 1260
+DormantOnFirstStartup 1
+DormantTimeoutDisabledByIdleStreams 0
+DoSCircuitCreationBurst 1000
+DoSCircuitCreationDefenseTimePeriod 300
+DoSCircuitCreationDefenseType 2
+DoSCircuitCreationEnabled 1
+DoSCircuitCreationMinConnections 10
+DoSCircuitCreationRate 100
+DoSConnectionDefenseType 2
+DoSConnectionEnabled 1
+DoSConnectionMaxConcurrentCount 6
+DoSRefuseSingleHopClientRendezvous 0
+DownloadExtraInfo 1
+EnforceDistinctSubnets 0
+EntryNodes potrzebie,triffid,cromulent
+EntryStatistics 1
+ExcludeExitNodes blaznort,kriffid,zeppelin
+ExcludeNodes 128.66.7.6
+ExitNodes 128.66.7.7,128.66.128.0/17,exitexit
+ExitPolicy accept *:80,reject *:*
+ExitPolicyRejectLocalInterfaces 1
+ExitPolicyRejectPrivate 0
+ExitPortStatistics 1
+ExitRelay 1
+ExtendAllowPrivateAddresses 1
+ExtendByEd25519ID 1
+ExtORPortCookieAuthFile /foobar
+ExtORPort 99
+FascistFirewall 1
+FetchDirInfoEarly 1
+FetchDirInfoExtraEarly 1
+FetchUselessDescriptors 1
+FirewallPorts 80,443,999
+GeoIPExcludeUnknown 1
+GeoIPFile /geoip
+GuardfractionFile /gff
+GuardLifetime 691200
+HeartbeatPeriod 2700
+IPv6Exit 1
+KeepalivePeriod 540
+KeyDirectory /keyz
+KISTSchedRunInterval 1
+Log notice file /logfile
+Log info file /logfile-verbose
+LogTimeGranularity 60000
+LongLivedPorts 9090
+MainloopStats 1
+MapAddress www.example.com:10.0.0.6
+MaxAdvertisedBandwidth 100
+MaxCircuitDirtiness 3600
+MaxClientCircuitsPending 127
+MaxConsensusAgeForDiffs 2629728
+MaxMemInQueues 314572800
+MaxOnionQueueDelay 60000
+MaxUnparseableDescSizeToLog 1048576
+MiddleNodes grommit,truffle,parcheesi
+MyFamily $ffffffffffffffffffffffffffffffffffffffff
+NewCircuitPeriod 7200
+Nickname nickname
+NodeFamily $ffffffffffffffffffffffffffffffffffffffff,$dddddddddddddddddddddddddddddddddddddddd
+NumCPUs 3
+NumDirectoryGuards 4
+NumEntryGuards 5
+NumPrimaryGuards 8
+OfflineMasterKey 1
+ORPort 2222
+OutboundBindAddress 10.0.0.7
+OutboundBindAddressExit 10.0.0.8
+OutboundBindAddressOR 10.0.0.9
+PerConnBWBurst 10485760
+PerConnBWRate 102400
+PidFile /piddy
+ProtocolWarnings 1
+PublishHidServDescriptors 0
+PublishServerDescriptor 0
+ReachableAddresses 0.0.0.0, *:*
+ReachableDirAddresses 128.0.0.0/1
+ReachableORAddresses 128.0.0.0/8
+RejectPlaintextPorts 23
+RelayBandwidthBurst 10000
+RelayBandwidthRate 1000
+RendPostPeriod 600
+RephistTrackTime 600
+SafeLogging 0
+Schedulers Vanilla,KISTLite,Kist
+ShutdownWaitLength 10
+SigningKeyLifetime 4838400
+Socks5Proxy 128.66.99.99:99
+Socks5ProxyPassword flynn
+Socks5ProxyUsername spaceparanoids
+SocksPolicy accept 127.0.0.0/24, reject *:*
+SocksPort 9099
+SocksTimeout 600
+SSLKeyLifetime 86400
+StrictNodes 1
+SyslogIdentityTag tortor
+TestSocks 1
+TokenBucketRefillInterval 1000
+TrackHostExits www.example.com
+TrackHostExitsExpire 3600
+TruncateLogFile 1
+UnixSocksGroupWritable 1
+UpdateBridgesFromAuthority 1
+UseDefaultFallbackDirs 0
+UseGuardFraction 1
+UseMicrodescriptors 0
+VirtualAddrNetworkIPv4 18.66.0.0/16
+VirtualAddrNetworkIPv6 [ff00::]/16
+WarnPlaintextPorts 7,11,23,1001
diff --git a/src/test/conf_examples/large_1/torrc b/src/test/conf_examples/large_1/torrc
new file mode 100644
index 0000000000..3f5b1e179f
--- /dev/null
+++ b/src/test/conf_examples/large_1/torrc
@@ -0,0 +1,165 @@
+AccountingMax 10 GB
+AccountingRule sum
+AccountingStart day 05:15
+Address 128.66.8.8
+AllowNonRFC953Hostnames 1
+AutomapHostsOnResolve 1
+AutomapHostsSuffixes .onions
+AvoidDiskWrites 1
+BandwidthBurst 2 GB
+BandwidthRate 1.5 GB
+Bridge 128.66.1.10:80
+CacheDirectory /this-is-a-cache
+CellStatistics 1
+CircuitBuildTimeout 200
+CircuitPadding 1
+CircuitsAvailableTimeout 10
+CircuitStreamTimeout 20
+ClientOnly 1
+ClientPreferIPv6DirPort 1
+ClientPreferIPv6ORPort 1
+ClientRejectInternalAddresses 0
+ClientUseIPv4 0
+ClientUseIPv6 1
+ConnDirectionStatistics 1
+ConnectionPadding 1
+ConnLimit 64
+ConsensusParams wombat=7
+ConstrainedSockets 1
+ConstrainedSockSize 10240
+ContactInfo long_config@example.com
+ControlPortFileGroupReadable 1
+ControlPort 9058
+CookieAuthentication 1
+CookieAuthFile /control/cookie
+CookieAuthFileGroupReadable 1
+CountPrivateBandwidth 1
+DataDirectory /data/dir
+DirAllowPrivateAddresses 1
+DirPolicy reject 128.66.1.1/32, accept *:*
+DirReqStatistics 0
+DirPort 99
+DirPortFrontPage /dirport/frontpage
+DisableDebuggerAttachment 0
+DisableNetwork 1
+DisableOOSCheck 0
+DNSPort 53535
+DormantCanceledByStartup 1
+DormantClientTimeout 21 minutes
+DormantOnFirstStartup 1
+DormantTimeoutDisabledByIdleStreams 0
+DoSCircuitCreationBurst 1000
+DoSCircuitCreationDefenseTimePeriod 5 minutes
+DoSCircuitCreationDefenseType 2
+DoSCircuitCreationEnabled 1
+DoSCircuitCreationMinConnections 10
+DoSCircuitCreationRate 100
+DoSConnectionDefenseType 2
+DoSConnectionEnabled 1
+DoSConnectionMaxConcurrentCount 6
+DoSRefuseSingleHopClientRendezvous 0
+DownloadExtraInfo 1
+EnforceDistinctSubnets 0
+EntryNodes potrzebie,triffid,cromulent
+EntryStatistics 1
+ExcludeExitNodes blaznort,kriffid,zeppelin
+ExcludeNodes 128.66.7.6
+ExitNodes 128.66.7.7,128.66.128.0/17,exitexit
+ExitPolicy accept *:80,reject *:*
+ExitPolicyRejectLocalInterfaces 1
+ExitPolicyRejectPrivate 0
+ExitPortStatistics 1
+ExitRelay 1
+ExtendAllowPrivateAddresses 1
+ExtendByEd25519ID 1
+ExtORPort 99
+ExtORPortCookieAuthFile /foobar
+ExtraInfoStatistics 1
+FascistFirewall 1
+FetchDirInfoEarly 1
+FetchDirInfoExtraEarly 1
+FetchHidServDescriptors 1
+FetchServerDescriptors 1
+FetchUselessDescriptors 1
+FirewallPorts 80,443,999
+GeoIPExcludeUnknown 1
+GeoIPFile /geoip
+GuardfractionFile /gff
+GuardLifetime 8 days
+HeartbeatPeriod 45 minutes
+IPv6Exit 1
+KeepalivePeriod 9 minutes
+KeyDirectory /keyz
+KISTSchedRunInterval 1 msec
+LearnCircuitBuildTimeout 1
+Log notice file /logfile
+Log info file /logfile-verbose
+LogTimeGranularity 1 minute
+LongLivedPorts 9090
+MainloopStats 1
+MapAddress www.example.com:10.0.0.6
+MaxAdvertisedBandwidth 100
+MaxCircuitDirtiness 1 hour
+MaxClientCircuitsPending 127
+MaxConsensusAgeForDiffs 1 month
+MaxMemInQueues 300 MB
+MaxOnionQueueDelay 60 seconds
+MaxUnparseableDescSizeToLog 1 MB
+MiddleNodes grommit, truffle, parcheesi
+MyFamily $ffffffffffffffffffffffffffffffffffffffff
+NewCircuitPeriod 2 hours
+Nickname nickname
+NodeFamily $ffffffffffffffffffffffffffffffffffffffff,$dddddddddddddddddddddddddddddddddddddddd
+NumCPUs 3
+NumDirectoryGuards 4
+NumEntryGuards 5
+NumPrimaryGuards 8
+OfflineMasterKey 1
+OptimisticData 1
+ORPort 2222
+OutboundBindAddress 10.0.0.7
+OutboundBindAddressExit 10.0.0.8
+OutboundBindAddressOR 10.0.0.9
+PaddingStatistics 1
+PerConnBWBurst 10 MB
+PerConnBWRate 100 kb
+PidFile /piddy
+ProtocolWarnings 1
+PublishHidServDescriptors 0
+PublishServerDescriptor 0
+ReachableAddresses 0.0.0.0, *:*
+ReachableDirAddresses 128.0.0.0/1
+ReachableORAddresses 128.0.0.0/8
+RejectPlaintextPorts 23
+RelayBandwidthBurst 10000
+RelayBandwidthRate 1000
+RendPostPeriod 10 minutes
+RephistTrackTime 10 minutes
+SafeLogging 0
+SafeSocks 0
+Schedulers Vanilla,KISTLite,Kist
+ShutdownWaitLength 10 seconds
+SigningKeyLifetime 8 weeks
+Socks5Proxy 128.66.99.99:99
+Socks5ProxyPassword flynn
+Socks5ProxyUsername spaceparanoids
+SocksPolicy accept 127.0.0.0/24, reject *:*
+SocksPort 9099
+SocksTimeout 10 minutes
+SSLKeyLifetime 1 day
+StrictNodes 1
+SyslogIdentityTag tortor
+TestSocks 1
+TokenBucketRefillInterval 1 second
+TrackHostExits www.example.com
+TrackHostExitsExpire 1 hour
+TruncateLogFile 1
+UnixSocksGroupWritable 1
+UpdateBridgesFromAuthority 1
+UseDefaultFallbackDirs 0
+UseEntryGuards 1
+UseGuardFraction 1
+UseMicrodescriptors 0
+VirtualAddrNetworkIPv4 18.66.0.0/16
+VirtualAddrNetworkIPv6 [ff00::]/16
+WarnPlaintextPorts 7,11,23,1001
diff --git a/src/test/conf_examples/lzma_zstd_1/expected b/src/test/conf_examples/lzma_zstd_1/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log b/src/test/conf_examples/lzma_zstd_1/expected_log
new file mode 100644
index 0000000000..f143b23102
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, Libzstd N/A and .* .* as libc
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma
new file mode 100644
index 0000000000..abb4731abc
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, Libzstd N/A and .* .* as libc
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd
new file mode 100644
index 0000000000..b4e45772dd
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc \ No newline at end of file
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_zstd b/src/test/conf_examples/lzma_zstd_1/expected_log_zstd
new file mode 100644
index 0000000000..994b46974b
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log_zstd
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, Libzstd .* and .* .* as libc \ No newline at end of file
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_lzma b/src/test/conf_examples/lzma_zstd_1/expected_lzma
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_lzma
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_lzma_zstd b/src/test/conf_examples/lzma_zstd_1/expected_lzma_zstd
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_lzma_zstd
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_zstd b/src/test/conf_examples/lzma_zstd_1/expected_zstd
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/expected_zstd
diff --git a/src/test/conf_examples/lzma_zstd_1/torrc b/src/test/conf_examples/lzma_zstd_1/torrc
new file mode 100644
index 0000000000..f873d79028
--- /dev/null
+++ b/src/test/conf_examples/lzma_zstd_1/torrc
@@ -0,0 +1 @@
+# This test checks for the optional library list in tor's logs
diff --git a/src/test/conf_examples/missing_cl_arg/cmdline b/src/test/conf_examples/missing_cl_arg/cmdline
new file mode 100644
index 0000000000..7fc4d0a54d
--- /dev/null
+++ b/src/test/conf_examples/missing_cl_arg/cmdline
@@ -0,0 +1 @@
+--hash-password
diff --git a/src/test/conf_examples/missing_cl_arg/error b/src/test/conf_examples/missing_cl_arg/error
new file mode 100644
index 0000000000..61dbeac8aa
--- /dev/null
+++ b/src/test/conf_examples/missing_cl_arg/error
@@ -0,0 +1 @@
+Command-line option '--hash-password' with no value.
diff --git a/src/test/conf_examples/missing_cl_arg/torrc b/src/test/conf_examples/missing_cl_arg/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/missing_cl_arg/torrc
diff --git a/src/test/conf_examples/multiple_routerset_1/expected b/src/test/conf_examples/multiple_routerset_1/expected
new file mode 100644
index 0000000000..9087aaff06
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_1/expected
@@ -0,0 +1 @@
+EntryNodes 127.0.0.1,127.0.0.2,127.0.0.3
diff --git a/src/test/conf_examples/multiple_routerset_1/expected_log b/src/test/conf_examples/multiple_routerset_1/expected_log
new file mode 100644
index 0000000000..a4b98345d6
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_1/expected_log
@@ -0,0 +1 @@
+Configuration was valid \ No newline at end of file
diff --git a/src/test/conf_examples/multiple_routerset_1/torrc b/src/test/conf_examples/multiple_routerset_1/torrc
new file mode 100644
index 0000000000..44978e4b38
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_1/torrc
@@ -0,0 +1,2 @@
+EntryNodes 127.0.0.1
+EntryNodes 127.0.0.2,127.0.0.3 \ No newline at end of file
diff --git a/src/test/conf_examples/multiple_routerset_2/cmdline b/src/test/conf_examples/multiple_routerset_2/cmdline
new file mode 100644
index 0000000000..d6e7970e53
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_2/cmdline
@@ -0,0 +1 @@
+EntryNodes 127.0.0.4 \ No newline at end of file
diff --git a/src/test/conf_examples/multiple_routerset_2/expected b/src/test/conf_examples/multiple_routerset_2/expected
new file mode 100644
index 0000000000..34c893df79
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_2/expected
@@ -0,0 +1 @@
+EntryNodes 127.0.0.4
diff --git a/src/test/conf_examples/multiple_routerset_2/expected_log b/src/test/conf_examples/multiple_routerset_2/expected_log
new file mode 100644
index 0000000000..a4b98345d6
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_2/expected_log
@@ -0,0 +1 @@
+Configuration was valid \ No newline at end of file
diff --git a/src/test/conf_examples/multiple_routerset_2/torrc b/src/test/conf_examples/multiple_routerset_2/torrc
new file mode 100644
index 0000000000..44978e4b38
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_2/torrc
@@ -0,0 +1,2 @@
+EntryNodes 127.0.0.1
+EntryNodes 127.0.0.2,127.0.0.3 \ No newline at end of file
diff --git a/src/test/conf_examples/multiple_routerset_3/cmdline b/src/test/conf_examples/multiple_routerset_3/cmdline
new file mode 100644
index 0000000000..425f383bc3
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_3/cmdline
@@ -0,0 +1 @@
++EntryNodes 127.0.0.4 \ No newline at end of file
diff --git a/src/test/conf_examples/multiple_routerset_3/expected b/src/test/conf_examples/multiple_routerset_3/expected
new file mode 100644
index 0000000000..196b4814f8
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_3/expected
@@ -0,0 +1 @@
+EntryNodes 127.0.0.1,127.0.0.2,127.0.0.3,127.0.0.4
diff --git a/src/test/conf_examples/multiple_routerset_3/expected_log b/src/test/conf_examples/multiple_routerset_3/expected_log
new file mode 100644
index 0000000000..a4b98345d6
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_3/expected_log
@@ -0,0 +1 @@
+Configuration was valid \ No newline at end of file
diff --git a/src/test/conf_examples/multiple_routerset_3/torrc b/src/test/conf_examples/multiple_routerset_3/torrc
new file mode 100644
index 0000000000..44978e4b38
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_3/torrc
@@ -0,0 +1,2 @@
+EntryNodes 127.0.0.1
+EntryNodes 127.0.0.2,127.0.0.3 \ No newline at end of file
diff --git a/src/test/conf_examples/multiple_routerset_4/cmdline b/src/test/conf_examples/multiple_routerset_4/cmdline
new file mode 100644
index 0000000000..478c1abe74
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_4/cmdline
@@ -0,0 +1 @@
+/EntryNodes \ No newline at end of file
diff --git a/src/test/conf_examples/multiple_routerset_4/expected b/src/test/conf_examples/multiple_routerset_4/expected
new file mode 100644
index 0000000000..bc790c86e3
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_4/expected
@@ -0,0 +1 @@
+ControlSocket 1234
diff --git a/src/test/conf_examples/multiple_routerset_4/expected_log b/src/test/conf_examples/multiple_routerset_4/expected_log
new file mode 100644
index 0000000000..a4b98345d6
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_4/expected_log
@@ -0,0 +1 @@
+Configuration was valid \ No newline at end of file
diff --git a/src/test/conf_examples/multiple_routerset_4/torrc b/src/test/conf_examples/multiple_routerset_4/torrc
new file mode 100644
index 0000000000..dad8cb694e
--- /dev/null
+++ b/src/test/conf_examples/multiple_routerset_4/torrc
@@ -0,0 +1,3 @@
+ControlSocket 1234 # dummy to prevent empty output
+EntryNodes 127.0.0.1
+EntryNodes 127.0.0.2,127.0.0.3 \ No newline at end of file
diff --git a/src/test/conf_examples/nss_1/expected b/src/test/conf_examples/nss_1/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/nss_1/expected
diff --git a/src/test/conf_examples/nss_1/expected_log b/src/test/conf_examples/nss_1/expected_log
new file mode 100644
index 0000000000..38f1febda5
--- /dev/null
+++ b/src/test/conf_examples/nss_1/expected_log
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, OpenSSL .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc
diff --git a/src/test/conf_examples/nss_1/expected_log_nss b/src/test/conf_examples/nss_1/expected_log_nss
new file mode 100644
index 0000000000..bcbfa2cf6b
--- /dev/null
+++ b/src/test/conf_examples/nss_1/expected_log_nss
@@ -0,0 +1 @@
+Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc
diff --git a/src/test/conf_examples/nss_1/expected_nss b/src/test/conf_examples/nss_1/expected_nss
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/nss_1/expected_nss
diff --git a/src/test/conf_examples/nss_1/torrc b/src/test/conf_examples/nss_1/torrc
new file mode 100644
index 0000000000..f873d79028
--- /dev/null
+++ b/src/test/conf_examples/nss_1/torrc
@@ -0,0 +1 @@
+# This test checks for the optional library list in tor's logs
diff --git a/src/test/conf_examples/obsolete_1/expected b/src/test/conf_examples/obsolete_1/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/obsolete_1/expected
diff --git a/src/test/conf_examples/obsolete_1/expected_log b/src/test/conf_examples/obsolete_1/expected_log
new file mode 100644
index 0000000000..52f6f70a2e
--- /dev/null
+++ b/src/test/conf_examples/obsolete_1/expected_log
@@ -0,0 +1 @@
+Skipping obsolete configuration option
diff --git a/src/test/conf_examples/obsolete_1/torrc b/src/test/conf_examples/obsolete_1/torrc
new file mode 100644
index 0000000000..e711fe4065
--- /dev/null
+++ b/src/test/conf_examples/obsolete_1/torrc
@@ -0,0 +1,70 @@
+# These options are obsolete as of 0.4.2
+# Obsolete options without arguments, or with an empty argument,
+# are silently ignored. So we give each one of these options an argument.
+AllowDotExit 1
+AllowInvalidNodes 1
+AllowSingleHopCircuits 1
+AllowSingleHopExits 1
+AlternateHSAuthority 1
+AuthDirBadDir 1
+AuthDirBadDirCCs 1
+AuthDirRejectUnlisted 1
+AuthDirListBadDirs 1
+AuthDirMaxServersPerAuthAddr 1
+CircuitIdleTimeout 1
+ControlListenAddress 1
+DirListenAddress 1
+DisableIOCP 1
+DisableV2DirectoryInfo_ 1
+DynamicDHGroups 1
+DNSListenAddress 1
+TestingEnableTbEmptyEvent 1
+ExcludeSingleHopRelays 1
+FallbackNetworkstatusFile 1
+FastFirstHopPK 1
+FetchV2Networkstatus 1
+Group 1
+HidServDirectoryV2 1
+CloseHSClientCircuitsImmediatelyOnTimeout 1
+CloseHSServiceRendCircuitsImmediatelyOnTimeout 1
+MaxOnionsPending 1
+NamingAuthoritativeDirectory 1
+NATDListenAddress 1
+PredictedPortsRelevanceTime 1
+WarnUnsafeSocks 1
+ORListenAddress 1
+PathBiasDisableRate 1
+PathBiasScaleFactor 1
+PathBiasMultFactor 1
+PathBiasUseCloseCounts 1
+PortForwarding 1
+PortForwardingHelper 1
+PreferTunneledDirConns 1
+RecommendedPackages 1
+RunTesting 1
+SchedulerLowWaterMark__ 1
+SchedulerHighWaterMark__ 1
+SchedulerMaxFlushCells__ 1
+SocksListenAddress 1
+StrictEntryNodes 1
+StrictExitNodes 1
+Support022HiddenServices 1
+Tor2webMode 1
+Tor2webRendezvousPoints 1
+TLSECGroup 1
+TransListenAddress 1
+TunnelDirConns 1
+UseEntryGuardsAsDirGuards 1
+UseNTorHandshake 1
+UserspaceIOCPBuffers 1
+V1AuthoritativeDirectory 1
+V2AuthoritativeDirectory 1
+VoteOnHidServDirectoriesV2 1
+UseFilteringSSLBufferevents 1
+__UseFilteringSSLBufferevents 1
+TestingConsensusMaxDownloadTries 1
+ClientBootstrapConsensusMaxDownloadTries 1
+ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries 1
+TestingDescriptorMaxDownloadTries 1
+TestingMicrodescMaxDownloadTries 1
+TestingCertMaxDownloadTries 1
diff --git a/src/test/conf_examples/obsolete_2/expected b/src/test/conf_examples/obsolete_2/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/obsolete_2/expected
diff --git a/src/test/conf_examples/obsolete_2/expected_log b/src/test/conf_examples/obsolete_2/expected_log
new file mode 100644
index 0000000000..2160355ee9
--- /dev/null
+++ b/src/test/conf_examples/obsolete_2/expected_log
@@ -0,0 +1 @@
+Read configuration file .*obsolete_2[./]*torrc
diff --git a/src/test/conf_examples/obsolete_2/torrc b/src/test/conf_examples/obsolete_2/torrc
new file mode 100644
index 0000000000..b83e7a7369
--- /dev/null
+++ b/src/test/conf_examples/obsolete_2/torrc
@@ -0,0 +1,5 @@
+# This option has been obsolete for some time
+# Obsolete options without arguments, or with an empty argument,
+# are silently ignored.
+AllowDotExit
+AllowInvalidNodes ""
diff --git a/src/test/conf_examples/obsolete_3/expected b/src/test/conf_examples/obsolete_3/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/obsolete_3/expected
diff --git a/src/test/conf_examples/obsolete_3/expected_log b/src/test/conf_examples/obsolete_3/expected_log
new file mode 100644
index 0000000000..82d76ec818
--- /dev/null
+++ b/src/test/conf_examples/obsolete_3/expected_log
@@ -0,0 +1 @@
+Skipping obsolete configuration option "AllowDotExit"
diff --git a/src/test/conf_examples/obsolete_3/torrc b/src/test/conf_examples/obsolete_3/torrc
new file mode 100644
index 0000000000..e0efe752bf
--- /dev/null
+++ b/src/test/conf_examples/obsolete_3/torrc
@@ -0,0 +1,4 @@
+# This option has been obsolete for some time
+# Obsolete options without arguments, or with an empty argument,
+# are silently ignored. So we give this option an argument.
+AllowDotExit 1
diff --git a/src/test/conf_examples/ops_1/cmdline b/src/test/conf_examples/ops_1/cmdline
new file mode 100644
index 0000000000..2bb9bfa132
--- /dev/null
+++ b/src/test/conf_examples/ops_1/cmdline
@@ -0,0 +1 @@
+ORPort 1000
diff --git a/src/test/conf_examples/ops_1/error_no_dirauth_relay b/src/test/conf_examples/ops_1/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/ops_1/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/ops_1/expected b/src/test/conf_examples/ops_1/expected
new file mode 100644
index 0000000000..84be6a70e2
--- /dev/null
+++ b/src/test/conf_examples/ops_1/expected
@@ -0,0 +1,2 @@
+Nickname Unnamed
+ORPort 1000
diff --git a/src/test/conf_examples/ops_1/expected_log b/src/test/conf_examples/ops_1/expected_log
new file mode 100644
index 0000000000..b785d7fb52
--- /dev/null
+++ b/src/test/conf_examples/ops_1/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_1[./]*torrc
diff --git a/src/test/conf_examples/ops_1/torrc b/src/test/conf_examples/ops_1/torrc
new file mode 100644
index 0000000000..daf8ae60fe
--- /dev/null
+++ b/src/test/conf_examples/ops_1/torrc
@@ -0,0 +1,3 @@
+# We'll replace this option on the command line.
+
+ORPort 9999
diff --git a/src/test/conf_examples/ops_2/cmdline b/src/test/conf_examples/ops_2/cmdline
new file mode 100644
index 0000000000..fdd48a045c
--- /dev/null
+++ b/src/test/conf_examples/ops_2/cmdline
@@ -0,0 +1 @@
+/ORPort
diff --git a/src/test/conf_examples/ops_2/expected b/src/test/conf_examples/ops_2/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/ops_2/expected
diff --git a/src/test/conf_examples/ops_2/expected_log b/src/test/conf_examples/ops_2/expected_log
new file mode 100644
index 0000000000..17fbc3ffbf
--- /dev/null
+++ b/src/test/conf_examples/ops_2/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_2[./]*torrc
diff --git a/src/test/conf_examples/ops_2/torrc b/src/test/conf_examples/ops_2/torrc
new file mode 100644
index 0000000000..21fcc93f9a
--- /dev/null
+++ b/src/test/conf_examples/ops_2/torrc
@@ -0,0 +1,3 @@
+# We'll remove this option on the command line, and not replace it.
+
+ORPort 9999
diff --git a/src/test/conf_examples/ops_3/cmdline b/src/test/conf_examples/ops_3/cmdline
new file mode 100644
index 0000000000..e4965d26f8
--- /dev/null
+++ b/src/test/conf_examples/ops_3/cmdline
@@ -0,0 +1 @@
++ORPort 1000
diff --git a/src/test/conf_examples/ops_3/error_no_dirauth_relay b/src/test/conf_examples/ops_3/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/ops_3/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/ops_3/expected b/src/test/conf_examples/ops_3/expected
new file mode 100644
index 0000000000..569d26b577
--- /dev/null
+++ b/src/test/conf_examples/ops_3/expected
@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort 9999
+ORPort 1000
diff --git a/src/test/conf_examples/ops_3/expected_log b/src/test/conf_examples/ops_3/expected_log
new file mode 100644
index 0000000000..151498f0df
--- /dev/null
+++ b/src/test/conf_examples/ops_3/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_3[./]*torrc
diff --git a/src/test/conf_examples/ops_3/torrc b/src/test/conf_examples/ops_3/torrc
new file mode 100644
index 0000000000..14adf87d7f
--- /dev/null
+++ b/src/test/conf_examples/ops_3/torrc
@@ -0,0 +1,3 @@
+# We will extend this option on the command line
+
+ORPort 9999
diff --git a/src/test/conf_examples/ops_4/error_no_dirauth_relay b/src/test/conf_examples/ops_4/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/ops_4/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/ops_4/expected b/src/test/conf_examples/ops_4/expected
new file mode 100644
index 0000000000..bf52f6a330
--- /dev/null
+++ b/src/test/conf_examples/ops_4/expected
@@ -0,0 +1,2 @@
+Nickname Unnamed
+ORPort 9099
diff --git a/src/test/conf_examples/ops_4/expected_log b/src/test/conf_examples/ops_4/expected_log
new file mode 100644
index 0000000000..7632b2290c
--- /dev/null
+++ b/src/test/conf_examples/ops_4/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_4[./]*torrc\.defaults
diff --git a/src/test/conf_examples/ops_4/torrc b/src/test/conf_examples/ops_4/torrc
new file mode 100644
index 0000000000..dcec2aa95d
--- /dev/null
+++ b/src/test/conf_examples/ops_4/torrc
@@ -0,0 +1,3 @@
+# This value is unadorned, so replaces the one from defaults.torrc.
+
+ORPort 9099
diff --git a/src/test/conf_examples/ops_4/torrc.defaults b/src/test/conf_examples/ops_4/torrc.defaults
new file mode 100644
index 0000000000..04cd0393c6
--- /dev/null
+++ b/src/test/conf_examples/ops_4/torrc.defaults
@@ -0,0 +1 @@
+ORPort 9000
diff --git a/src/test/conf_examples/ops_5/error_no_dirauth_relay b/src/test/conf_examples/ops_5/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/ops_5/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/ops_5/expected b/src/test/conf_examples/ops_5/expected
new file mode 100644
index 0000000000..288721da53
--- /dev/null
+++ b/src/test/conf_examples/ops_5/expected
@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort 9000
+ORPort 9099
diff --git a/src/test/conf_examples/ops_5/expected_log b/src/test/conf_examples/ops_5/expected_log
new file mode 100644
index 0000000000..ec63cb0638
--- /dev/null
+++ b/src/test/conf_examples/ops_5/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_5[./]*torrc\.defaults
diff --git a/src/test/conf_examples/ops_5/torrc b/src/test/conf_examples/ops_5/torrc
new file mode 100644
index 0000000000..3284fc1c55
--- /dev/null
+++ b/src/test/conf_examples/ops_5/torrc
@@ -0,0 +1,3 @@
+# This value has a plus, and so extends the one from defaults.torrc.
+
++ORPort 9099
diff --git a/src/test/conf_examples/ops_5/torrc.defaults b/src/test/conf_examples/ops_5/torrc.defaults
new file mode 100644
index 0000000000..04cd0393c6
--- /dev/null
+++ b/src/test/conf_examples/ops_5/torrc.defaults
@@ -0,0 +1 @@
+ORPort 9000
diff --git a/src/test/conf_examples/ops_6/expected b/src/test/conf_examples/ops_6/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/ops_6/expected
diff --git a/src/test/conf_examples/ops_6/expected_log b/src/test/conf_examples/ops_6/expected_log
new file mode 100644
index 0000000000..f9b1ca0412
--- /dev/null
+++ b/src/test/conf_examples/ops_6/expected_log
@@ -0,0 +1 @@
+Read configuration file .*ops_6[./]*torrc\.defaults
diff --git a/src/test/conf_examples/ops_6/torrc b/src/test/conf_examples/ops_6/torrc
new file mode 100644
index 0000000000..4d51caaff7
--- /dev/null
+++ b/src/test/conf_examples/ops_6/torrc
@@ -0,0 +1,3 @@
+# This value has a slash, and so clears the one from defaults.torrc.
+
+/ORPort
diff --git a/src/test/conf_examples/ops_6/torrc.defaults b/src/test/conf_examples/ops_6/torrc.defaults
new file mode 100644
index 0000000000..04cd0393c6
--- /dev/null
+++ b/src/test/conf_examples/ops_6/torrc.defaults
@@ -0,0 +1 @@
+ORPort 9000
diff --git a/src/test/conf_examples/pt_01/expected b/src/test/conf_examples/pt_01/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/pt_01/expected
diff --git a/src/test/conf_examples/pt_01/expected_log b/src/test/conf_examples/pt_01/expected_log
new file mode 100644
index 0000000000..65bfa7a7b7
--- /dev/null
+++ b/src/test/conf_examples/pt_01/expected_log
@@ -0,0 +1 @@
+Linelist option 'ExtORPort' has no value\. Skipping
diff --git a/src/test/conf_examples/pt_01/torrc b/src/test/conf_examples/pt_01/torrc
new file mode 100644
index 0000000000..574bb32a0d
--- /dev/null
+++ b/src/test/conf_examples/pt_01/torrc
@@ -0,0 +1,7 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Empty linelist values are ignored with a warning
+ExtORPort
+ServerTransportPlugin
+ServerTransportListenAddr
+ServerTransportOptions
diff --git a/src/test/conf_examples/pt_02/error b/src/test/conf_examples/pt_02/error
new file mode 100644
index 0000000000..ce28eab729
--- /dev/null
+++ b/src/test/conf_examples/pt_02/error
@@ -0,0 +1 @@
+Invalid ExtORPort configuration
diff --git a/src/test/conf_examples/pt_02/expected_log_no_dirauth_relay b/src/test/conf_examples/pt_02/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..0e48dca7fd
--- /dev/null
+++ b/src/test/conf_examples/pt_02/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*pt_02[./]*torrc
diff --git a/src/test/conf_examples/pt_02/expected_no_dirauth_relay b/src/test/conf_examples/pt_02/expected_no_dirauth_relay
new file mode 100644
index 0000000000..f5cd26e6b7
--- /dev/null
+++ b/src/test/conf_examples/pt_02/expected_no_dirauth_relay
@@ -0,0 +1,8 @@
+ExtORPort illegal_hostname_chars$()^*%(%
+ServerTransportListenAddr bad
+ServerTransportListenAddr bad2 illegal_hostname_chars$()^*%(%
+ServerTransportOptions bad
+ServerTransportOptions bad2 not_kv
+ServerTransportPlugin bad
+ServerTransportPlugin bad2 exec
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_02/torrc b/src/test/conf_examples/pt_02/torrc
new file mode 100644
index 0000000000..825f2c4be4
--- /dev/null
+++ b/src/test/conf_examples/pt_02/torrc
@@ -0,0 +1,13 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Bad options are also ignored
+# (Unless the relay module is disabled, because they are relay-only
+# options. We'll ignore all relay-only options in #32395.)
+ExtORPort illegal_hostname_chars$()^*%(%#%)#(%*
+ServerTransportPlugin bad
+ServerTransportPlugin bad2 exec
+ServerTransportPlugin bad3 exec /
+ServerTransportListenAddr bad
+ServerTransportListenAddr bad2 illegal_hostname_chars$()^*%(%#%)#(%*
+ServerTransportOptions bad
+ServerTransportOptions bad2 not_kv
diff --git a/src/test/conf_examples/pt_03/expected b/src/test/conf_examples/pt_03/expected
new file mode 100644
index 0000000000..f849f2a78f
--- /dev/null
+++ b/src/test/conf_examples/pt_03/expected
@@ -0,0 +1 @@
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_03/expected_log b/src/test/conf_examples/pt_03/expected_log
new file mode 100644
index 0000000000..285a189c28
--- /dev/null
+++ b/src/test/conf_examples/pt_03/expected_log
@@ -0,0 +1 @@
+We use pluggable transports but the Extended ORPort is disabled
diff --git a/src/test/conf_examples/pt_03/expected_log_no_dirauth_relay b/src/test/conf_examples/pt_03/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..88f4e5bdfb
--- /dev/null
+++ b/src/test/conf_examples/pt_03/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*pt_03[./]*torrc
diff --git a/src/test/conf_examples/pt_03/expected_no_dirauth_relay b/src/test/conf_examples/pt_03/expected_no_dirauth_relay
new file mode 100644
index 0000000000..f849f2a78f
--- /dev/null
+++ b/src/test/conf_examples/pt_03/expected_no_dirauth_relay
@@ -0,0 +1 @@
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_03/torrc b/src/test/conf_examples/pt_03/torrc
new file mode 100644
index 0000000000..9868c39b26
--- /dev/null
+++ b/src/test/conf_examples/pt_03/torrc
@@ -0,0 +1,4 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Plugin, but no ExtORPort
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_04/expected b/src/test/conf_examples/pt_04/expected
new file mode 100644
index 0000000000..9087f600e0
--- /dev/null
+++ b/src/test/conf_examples/pt_04/expected
@@ -0,0 +1,3 @@
+ExtORPortCookieAuthFile /
+ExtORPort 1
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_04/expected_log b/src/test/conf_examples/pt_04/expected_log
new file mode 100644
index 0000000000..5b3ab51d25
--- /dev/null
+++ b/src/test/conf_examples/pt_04/expected_log
@@ -0,0 +1 @@
+Tor is not configured as a relay but you specified a ServerTransportPlugin line.*The ServerTransportPlugin line will be ignored
diff --git a/src/test/conf_examples/pt_04/expected_log_no_dirauth_relay b/src/test/conf_examples/pt_04/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..2b989bf320
--- /dev/null
+++ b/src/test/conf_examples/pt_04/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*pt_04[./]*torrc
diff --git a/src/test/conf_examples/pt_04/expected_no_dirauth_relay b/src/test/conf_examples/pt_04/expected_no_dirauth_relay
new file mode 100644
index 0000000000..9087f600e0
--- /dev/null
+++ b/src/test/conf_examples/pt_04/expected_no_dirauth_relay
@@ -0,0 +1,3 @@
+ExtORPortCookieAuthFile /
+ExtORPort 1
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_04/torrc b/src/test/conf_examples/pt_04/torrc
new file mode 100644
index 0000000000..18bb28f9cf
--- /dev/null
+++ b/src/test/conf_examples/pt_04/torrc
@@ -0,0 +1,6 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try a bad cookie auth file
+ExtORPort 1
+ExtORPortCookieAuthFile /
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_05/error_no_dirauth_relay b/src/test/conf_examples/pt_05/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/pt_05/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/pt_05/expected b/src/test/conf_examples/pt_05/expected
new file mode 100644
index 0000000000..61568bb9ac
--- /dev/null
+++ b/src/test/conf_examples/pt_05/expected
@@ -0,0 +1,4 @@
+ExtORPort 1
+Nickname Unnamed
+ORPort 2
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_05/expected_log b/src/test/conf_examples/pt_05/expected_log
new file mode 100644
index 0000000000..c05a0931d6
--- /dev/null
+++ b/src/test/conf_examples/pt_05/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set
diff --git a/src/test/conf_examples/pt_05/torrc b/src/test/conf_examples/pt_05/torrc
new file mode 100644
index 0000000000..55c569bb1b
--- /dev/null
+++ b/src/test/conf_examples/pt_05/torrc
@@ -0,0 +1,6 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try a valid minimal config
+ORPort 2
+ExtORPort 1
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_06/expected b/src/test/conf_examples/pt_06/expected
new file mode 100644
index 0000000000..d5788b92c9
--- /dev/null
+++ b/src/test/conf_examples/pt_06/expected
@@ -0,0 +1,6 @@
+ExtORPortCookieAuthFile /
+ExtORPortCookieAuthFileGroupReadable 1
+ExtORPort 1
+ServerTransportListenAddr bad3 127.0.0.1:2
+ServerTransportOptions bad3 a=b
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_06/expected_log b/src/test/conf_examples/pt_06/expected_log
new file mode 100644
index 0000000000..5b3ab51d25
--- /dev/null
+++ b/src/test/conf_examples/pt_06/expected_log
@@ -0,0 +1 @@
+Tor is not configured as a relay but you specified a ServerTransportPlugin line.*The ServerTransportPlugin line will be ignored
diff --git a/src/test/conf_examples/pt_06/expected_log_no_dirauth_relay b/src/test/conf_examples/pt_06/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..f35a380c9f
--- /dev/null
+++ b/src/test/conf_examples/pt_06/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*pt_06[./]*torrc
diff --git a/src/test/conf_examples/pt_06/expected_no_dirauth_relay b/src/test/conf_examples/pt_06/expected_no_dirauth_relay
new file mode 100644
index 0000000000..d5788b92c9
--- /dev/null
+++ b/src/test/conf_examples/pt_06/expected_no_dirauth_relay
@@ -0,0 +1,6 @@
+ExtORPortCookieAuthFile /
+ExtORPortCookieAuthFileGroupReadable 1
+ExtORPort 1
+ServerTransportListenAddr bad3 127.0.0.1:2
+ServerTransportOptions bad3 a=b
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_06/torrc b/src/test/conf_examples/pt_06/torrc
new file mode 100644
index 0000000000..20cfc329a7
--- /dev/null
+++ b/src/test/conf_examples/pt_06/torrc
@@ -0,0 +1,9 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try a config with all the options
+ExtORPort 1
+ExtORPortCookieAuthFile /
+ExtORPortCookieAuthFileGroupReadable 1
+ServerTransportPlugin bad3 exec /
+ServerTransportListenAddr bad3 127.0.0.1:2
+ServerTransportOptions bad3 a=b
diff --git a/src/test/conf_examples/pt_07/error_no_dirauth_relay b/src/test/conf_examples/pt_07/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/pt_07/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/pt_07/expected b/src/test/conf_examples/pt_07/expected
new file mode 100644
index 0000000000..c3a75dc407
--- /dev/null
+++ b/src/test/conf_examples/pt_07/expected
@@ -0,0 +1,4 @@
+ExtORPort 2.2.2.2:1
+Nickname Unnamed
+ORPort 2
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_07/expected_log b/src/test/conf_examples/pt_07/expected_log
new file mode 100644
index 0000000000..5afaf02ba9
--- /dev/null
+++ b/src/test/conf_examples/pt_07/expected_log
@@ -0,0 +1 @@
+You specified a public address .* for ExtORPort
diff --git a/src/test/conf_examples/pt_07/torrc b/src/test/conf_examples/pt_07/torrc
new file mode 100644
index 0000000000..40eaf50e64
--- /dev/null
+++ b/src/test/conf_examples/pt_07/torrc
@@ -0,0 +1,6 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try a valid config with a risky ExtORPort address
+ORPort 2
+ExtORPort 2.2.2.2:1
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_08/error b/src/test/conf_examples/pt_08/error
new file mode 100644
index 0000000000..7931bbb4b9
--- /dev/null
+++ b/src/test/conf_examples/pt_08/error
@@ -0,0 +1 @@
+ExtORPort does not support unix sockets \ No newline at end of file
diff --git a/src/test/conf_examples/pt_08/expected_log_no_dirauth_relay b/src/test/conf_examples/pt_08/expected_log_no_dirauth_relay
new file mode 100644
index 0000000000..79dcbc10ca
--- /dev/null
+++ b/src/test/conf_examples/pt_08/expected_log_no_dirauth_relay
@@ -0,0 +1 @@
+Read configuration file .*pt_08[./]*torrc
diff --git a/src/test/conf_examples/pt_08/expected_no_dirauth_relay b/src/test/conf_examples/pt_08/expected_no_dirauth_relay
new file mode 100644
index 0000000000..9a1a9bd1e4
--- /dev/null
+++ b/src/test/conf_examples/pt_08/expected_no_dirauth_relay
@@ -0,0 +1,2 @@
+ExtORPort unix:/
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_08/torrc b/src/test/conf_examples/pt_08/torrc
new file mode 100644
index 0000000000..6f1d79d706
--- /dev/null
+++ b/src/test/conf_examples/pt_08/torrc
@@ -0,0 +1,7 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try an invalid config with a unix socket for ExtORPort
+# (Unless the relay module is disabled, because they are relay-only
+# options. We'll ignore all relay-only options in #32395.)
+ExtORPort unix:/
+ServerTransportPlugin bad3 exec /
diff --git a/src/test/conf_examples/pt_09/error b/src/test/conf_examples/pt_09/error
new file mode 100644
index 0000000000..882b50a7bc
--- /dev/null
+++ b/src/test/conf_examples/pt_09/error
@@ -0,0 +1 @@
+Error parsing ServerTransportListenAddr address \ No newline at end of file
diff --git a/src/test/conf_examples/pt_09/error_no_dirauth_relay b/src/test/conf_examples/pt_09/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/pt_09/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/pt_09/torrc b/src/test/conf_examples/pt_09/torrc
new file mode 100644
index 0000000000..50a8e95b95
--- /dev/null
+++ b/src/test/conf_examples/pt_09/torrc
@@ -0,0 +1,7 @@
+# Relay PT tests
+# Options from relay/transport_config.c
+# Try a valid minimal config, with a bad ServerTransportListenAddr
+ORPort 2
+ExtORPort 1
+ServerTransportPlugin bad3 exec /
+ServerTransportListenAddr bad3 [aaaa::bbbb:ccccc]
diff --git a/src/test/conf_examples/relay_01/expected b/src/test/conf_examples/relay_01/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_examples/relay_01/expected
diff --git a/src/test/conf_examples/relay_01/expected_log b/src/test/conf_examples/relay_01/expected_log
new file mode 100644
index 0000000000..32e8c99d27
--- /dev/null
+++ b/src/test/conf_examples/relay_01/expected_log
@@ -0,0 +1 @@
+Linelist option 'ORPort' has no value\. Skipping
diff --git a/src/test/conf_examples/relay_01/torrc b/src/test/conf_examples/relay_01/torrc
new file mode 100644
index 0000000000..da3e85b427
--- /dev/null
+++ b/src/test/conf_examples/relay_01/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Empty linelist values are ignored with a warning
+ORPort
+DirPort
diff --git a/src/test/conf_examples/relay_02/error b/src/test/conf_examples/relay_02/error
new file mode 100644
index 0000000000..dd87d9f7e2
--- /dev/null
+++ b/src/test/conf_examples/relay_02/error
@@ -0,0 +1 @@
+Unrecognized value bad
diff --git a/src/test/conf_examples/relay_02/error_no_dirauth_relay b/src/test/conf_examples/relay_02/error_no_dirauth_relay
new file mode 100644
index 0000000000..dd87d9f7e2
--- /dev/null
+++ b/src/test/conf_examples/relay_02/error_no_dirauth_relay
@@ -0,0 +1 @@
+Unrecognized value bad
diff --git a/src/test/conf_examples/relay_02/torrc b/src/test/conf_examples/relay_02/torrc
new file mode 100644
index 0000000000..3eaa4403a9
--- /dev/null
+++ b/src/test/conf_examples/relay_02/torrc
@@ -0,0 +1,7 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Bad options are also ignored
+ORPort illegal_hostname_chars$()^*%(%#%)#(%*
+DirPort illegal_hostname_chars$()^*%(%#%)#(%*
+DirCache bad
+BridgeRelay bad
diff --git a/src/test/conf_examples/relay_03/error_no_dirauth_relay b/src/test/conf_examples/relay_03/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_03/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_03/expected b/src/test/conf_examples/relay_03/expected
new file mode 100644
index 0000000000..15056a8d1f
--- /dev/null
+++ b/src/test/conf_examples/relay_03/expected
@@ -0,0 +1,2 @@
+DirPort 1
+ORPort 0
diff --git a/src/test/conf_examples/relay_03/expected_log b/src/test/conf_examples/relay_03/expected_log
new file mode 100644
index 0000000000..46ab723e4a
--- /dev/null
+++ b/src/test/conf_examples/relay_03/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_03[./]*torrc
diff --git a/src/test/conf_examples/relay_03/torrc b/src/test/conf_examples/relay_03/torrc
new file mode 100644
index 0000000000..fd7da7bb95
--- /dev/null
+++ b/src/test/conf_examples/relay_03/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# DirPort, but no ORPort
+ORPort 0
+DirPort 1
diff --git a/src/test/conf_examples/relay_04/error_no_dirauth_relay b/src/test/conf_examples/relay_04/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_04/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_04/expected b/src/test/conf_examples/relay_04/expected
new file mode 100644
index 0000000000..1d25374ed1
--- /dev/null
+++ b/src/test/conf_examples/relay_04/expected
@@ -0,0 +1,2 @@
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_04/expected_log b/src/test/conf_examples/relay_04/expected_log
new file mode 100644
index 0000000000..c05a0931d6
--- /dev/null
+++ b/src/test/conf_examples/relay_04/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set
diff --git a/src/test/conf_examples/relay_04/torrc b/src/test/conf_examples/relay_04/torrc
new file mode 100644
index 0000000000..ff08b2376b
--- /dev/null
+++ b/src/test/conf_examples/relay_04/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid minimal config
+ORPort 1
diff --git a/src/test/conf_examples/relay_05/error_no_dirauth_relay b/src/test/conf_examples/relay_05/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_05/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_05/expected b/src/test/conf_examples/relay_05/expected
new file mode 100644
index 0000000000..ae58cee1af
--- /dev/null
+++ b/src/test/conf_examples/relay_05/expected
@@ -0,0 +1,3 @@
+DirPort 2
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_05/expected_log b/src/test/conf_examples/relay_05/expected_log
new file mode 100644
index 0000000000..483c2e2aae
--- /dev/null
+++ b/src/test/conf_examples/relay_05/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_05[./]*torrc
diff --git a/src/test/conf_examples/relay_05/torrc b/src/test/conf_examples/relay_05/torrc
new file mode 100644
index 0000000000..faeaad32a0
--- /dev/null
+++ b/src/test/conf_examples/relay_05/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid minimal directory mirror config
+ORPort 1
+DirPort 2
diff --git a/src/test/conf_examples/relay_06/error_no_dirauth_relay b/src/test/conf_examples/relay_06/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_06/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_06/expected b/src/test/conf_examples/relay_06/expected
new file mode 100644
index 0000000000..904c7339e0
--- /dev/null
+++ b/src/test/conf_examples/relay_06/expected
@@ -0,0 +1,3 @@
+BridgeRelay 1
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_06/expected_log b/src/test/conf_examples/relay_06/expected_log
new file mode 100644
index 0000000000..70eb18df19
--- /dev/null
+++ b/src/test/conf_examples/relay_06/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_06[./]*torrc
diff --git a/src/test/conf_examples/relay_06/torrc b/src/test/conf_examples/relay_06/torrc
new file mode 100644
index 0000000000..baeae8df5d
--- /dev/null
+++ b/src/test/conf_examples/relay_06/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid minimal bridge config
+ORPort 1
+BridgeRelay 1
diff --git a/src/test/conf_examples/relay_07/error_no_dirauth_relay b/src/test/conf_examples/relay_07/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_07/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_07/expected b/src/test/conf_examples/relay_07/expected
new file mode 100644
index 0000000000..79fa3e5a47
--- /dev/null
+++ b/src/test/conf_examples/relay_07/expected
@@ -0,0 +1,3 @@
+DirCache 0
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_07/expected_log b/src/test/conf_examples/relay_07/expected_log
new file mode 100644
index 0000000000..14729a7ab1
--- /dev/null
+++ b/src/test/conf_examples/relay_07/expected_log
@@ -0,0 +1 @@
+DirCache is disabled and we are configured as a relay
diff --git a/src/test/conf_examples/relay_07/torrc b/src/test/conf_examples/relay_07/torrc
new file mode 100644
index 0000000000..01ac138597
--- /dev/null
+++ b/src/test/conf_examples/relay_07/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid minimal non-directory cache config
+ORPort 1
+DirCache 0
diff --git a/src/test/conf_examples/relay_08/error_no_dirauth_relay b/src/test/conf_examples/relay_08/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_08/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_08/expected b/src/test/conf_examples/relay_08/expected
new file mode 100644
index 0000000000..904c7339e0
--- /dev/null
+++ b/src/test/conf_examples/relay_08/expected
@@ -0,0 +1,3 @@
+BridgeRelay 1
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_08/expected_log b/src/test/conf_examples/relay_08/expected_log
new file mode 100644
index 0000000000..b0168c803d
--- /dev/null
+++ b/src/test/conf_examples/relay_08/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_08[./]*torrc
diff --git a/src/test/conf_examples/relay_08/torrc b/src/test/conf_examples/relay_08/torrc
new file mode 100644
index 0000000000..9e2ff9465c
--- /dev/null
+++ b/src/test/conf_examples/relay_08/torrc
@@ -0,0 +1,6 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid config with all the bridge options
+ORPort 1
+BridgeRelay 1
+DirCache 1
diff --git a/src/test/conf_examples/relay_09/error_no_dirauth_relay b/src/test/conf_examples/relay_09/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_09/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_09/expected b/src/test/conf_examples/relay_09/expected
new file mode 100644
index 0000000000..ae58cee1af
--- /dev/null
+++ b/src/test/conf_examples/relay_09/expected
@@ -0,0 +1,3 @@
+DirPort 2
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_09/expected_log b/src/test/conf_examples/relay_09/expected_log
new file mode 100644
index 0000000000..d3ab4f6593
--- /dev/null
+++ b/src/test/conf_examples/relay_09/expected_log
@@ -0,0 +1 @@
+By default, Tor does not run as an exit relay
diff --git a/src/test/conf_examples/relay_09/torrc b/src/test/conf_examples/relay_09/torrc
new file mode 100644
index 0000000000..014eeca34b
--- /dev/null
+++ b/src/test/conf_examples/relay_09/torrc
@@ -0,0 +1,6 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid config with all the non-bridge options
+ORPort 1
+DirPort 2
+DirCache 1
diff --git a/src/test/conf_examples/relay_10/error_no_dirauth_relay b/src/test/conf_examples/relay_10/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_10/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_10/expected b/src/test/conf_examples/relay_10/expected
new file mode 100644
index 0000000000..904c7339e0
--- /dev/null
+++ b/src/test/conf_examples/relay_10/expected
@@ -0,0 +1,3 @@
+BridgeRelay 1
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_10/expected_log b/src/test/conf_examples/relay_10/expected_log
new file mode 100644
index 0000000000..5b81a904e5
--- /dev/null
+++ b/src/test/conf_examples/relay_10/expected_log
@@ -0,0 +1 @@
+Can't set a DirPort on a bridge relay
diff --git a/src/test/conf_examples/relay_10/torrc b/src/test/conf_examples/relay_10/torrc
new file mode 100644
index 0000000000..4318ebb45b
--- /dev/null
+++ b/src/test/conf_examples/relay_10/torrc
@@ -0,0 +1,7 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Try a valid config, that has a warning: Bridge, warn and disable DirPort
+ORPort 1
+DirPort 2
+DirCache 1
+BridgeRelay 1
diff --git a/src/test/conf_examples/relay_11/error b/src/test/conf_examples/relay_11/error
new file mode 100644
index 0000000000..8ed5c31bc7
--- /dev/null
+++ b/src/test/conf_examples/relay_11/error
@@ -0,0 +1 @@
+We are advertising an ORPort, but not actually listening on one
diff --git a/src/test/conf_examples/relay_11/error_no_dirauth_relay b/src/test/conf_examples/relay_11/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_11/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_11/torrc b/src/test/conf_examples/relay_11/torrc
new file mode 100644
index 0000000000..a1e13eb3ce
--- /dev/null
+++ b/src/test/conf_examples/relay_11/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Advertising but not listening: ORPort
+ORPort 1 NoListen
diff --git a/src/test/conf_examples/relay_12/error b/src/test/conf_examples/relay_12/error
new file mode 100644
index 0000000000..57706d6a7a
--- /dev/null
+++ b/src/test/conf_examples/relay_12/error
@@ -0,0 +1 @@
+We are advertising a DirPort, but not actually listening on one
diff --git a/src/test/conf_examples/relay_12/error_no_dirauth_relay b/src/test/conf_examples/relay_12/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_12/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_12/torrc b/src/test/conf_examples/relay_12/torrc
new file mode 100644
index 0000000000..4a7d398112
--- /dev/null
+++ b/src/test/conf_examples/relay_12/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Advertising but not listening: DirPort
+DirPort 1 NoListen
diff --git a/src/test/conf_examples/relay_13/error b/src/test/conf_examples/relay_13/error
new file mode 100644
index 0000000000..cd74247ea8
--- /dev/null
+++ b/src/test/conf_examples/relay_13/error
@@ -0,0 +1 @@
+We are listening on an ORPort, but not advertising any ORPorts
diff --git a/src/test/conf_examples/relay_13/error_no_dirauth_relay b/src/test/conf_examples/relay_13/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_13/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_13/torrc b/src/test/conf_examples/relay_13/torrc
new file mode 100644
index 0000000000..b76b72c0cc
--- /dev/null
+++ b/src/test/conf_examples/relay_13/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Listening but not advertising: ORPort
+ORPort 1 NoAdvertise
diff --git a/src/test/conf_examples/relay_14/error_no_dirauth_relay b/src/test/conf_examples/relay_14/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_14/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_14/expected b/src/test/conf_examples/relay_14/expected
new file mode 100644
index 0000000000..31bb1c2507
--- /dev/null
+++ b/src/test/conf_examples/relay_14/expected
@@ -0,0 +1 @@
+DirPort 1 NoAdvertise
diff --git a/src/test/conf_examples/relay_14/expected_log b/src/test/conf_examples/relay_14/expected_log
new file mode 100644
index 0000000000..9b0c820211
--- /dev/null
+++ b/src/test/conf_examples/relay_14/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_14[./]*torrc
diff --git a/src/test/conf_examples/relay_14/torrc b/src/test/conf_examples/relay_14/torrc
new file mode 100644
index 0000000000..15c6496c7e
--- /dev/null
+++ b/src/test/conf_examples/relay_14/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Listening but not advertising: DirPort
+DirPort 1 NoAdvertise
diff --git a/src/test/conf_examples/relay_15/error b/src/test/conf_examples/relay_15/error
new file mode 100644
index 0000000000..da30f0cd14
--- /dev/null
+++ b/src/test/conf_examples/relay_15/error
@@ -0,0 +1 @@
+Can't advertise more than one DirPort
diff --git a/src/test/conf_examples/relay_15/error_no_dirauth_relay b/src/test/conf_examples/relay_15/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_15/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_15/torrc b/src/test/conf_examples/relay_15/torrc
new file mode 100644
index 0000000000..e1f78ee6a0
--- /dev/null
+++ b/src/test/conf_examples/relay_15/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Advertising more than one DirPort
+DirPort 1
+DirPort 2
diff --git a/src/test/conf_examples/relay_16/error b/src/test/conf_examples/relay_16/error
new file mode 100644
index 0000000000..37b89ee572
--- /dev/null
+++ b/src/test/conf_examples/relay_16/error
@@ -0,0 +1 @@
+Configured public relay to listen only on an IPv6 address. Tor needs to listen on an IPv4 address
diff --git a/src/test/conf_examples/relay_16/error_no_dirauth_relay b/src/test/conf_examples/relay_16/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_16/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_16/torrc b/src/test/conf_examples/relay_16/torrc
new file mode 100644
index 0000000000..e544cd87a4
--- /dev/null
+++ b/src/test/conf_examples/relay_16/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# IPv6 ORPort only
+ORPort [::1]:2
diff --git a/src/test/conf_examples/relay_17/error_no_dirauth_relay b/src/test/conf_examples/relay_17/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_17/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_17/expected b/src/test/conf_examples/relay_17/expected
new file mode 100644
index 0000000000..3fb0c9db92
--- /dev/null
+++ b/src/test/conf_examples/relay_17/expected
@@ -0,0 +1,4 @@
+AccountingMax 1
+KeepBindCapabilities 0
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_17/expected_log b/src/test/conf_examples/relay_17/expected_log
new file mode 100644
index 0000000000..7711f90178
--- /dev/null
+++ b/src/test/conf_examples/relay_17/expected_log
@@ -0,0 +1 @@
+You have set AccountingMax to use hibernation
diff --git a/src/test/conf_examples/relay_17/torrc b/src/test/conf_examples/relay_17/torrc
new file mode 100644
index 0000000000..f63f36815e
--- /dev/null
+++ b/src/test/conf_examples/relay_17/torrc
@@ -0,0 +1,6 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Rebind warning
+ORPort 1
+AccountingMax 1
+KeepBindCapabilities 0
diff --git a/src/test/conf_examples/relay_18/error b/src/test/conf_examples/relay_18/error
new file mode 100644
index 0000000000..5b28d311b0
--- /dev/null
+++ b/src/test/conf_examples/relay_18/error
@@ -0,0 +1 @@
+Invalid DirPort configuration
diff --git a/src/test/conf_examples/relay_18/error_no_dirauth_relay b/src/test/conf_examples/relay_18/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_18/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_18/torrc b/src/test/conf_examples/relay_18/torrc
new file mode 100644
index 0000000000..67a0fd0dfb
--- /dev/null
+++ b/src/test/conf_examples/relay_18/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Bad DirPort
+DirPort illegal_hostname_chars$()^*%(%#%)#(%*
diff --git a/src/test/conf_examples/relay_19/error_no_dirauth_relay b/src/test/conf_examples/relay_19/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_19/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_19/expected b/src/test/conf_examples/relay_19/expected
new file mode 100644
index 0000000000..f077169c88
--- /dev/null
+++ b/src/test/conf_examples/relay_19/expected
@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort 1
+PublishServerDescriptor
diff --git a/src/test/conf_examples/relay_19/expected_log b/src/test/conf_examples/relay_19/expected_log
new file mode 100644
index 0000000000..17656ba2cf
--- /dev/null
+++ b/src/test/conf_examples/relay_19/expected_log
@@ -0,0 +1 @@
+Read configuration file .*relay_19[./]*torrc
diff --git a/src/test/conf_examples/relay_19/torrc b/src/test/conf_examples/relay_19/torrc
new file mode 100644
index 0000000000..fd2cd91fa5
--- /dev/null
+++ b/src/test/conf_examples/relay_19/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Minimal PublishServerDescriptor
+ORPort 1
+PublishServerDescriptor
diff --git a/src/test/conf_examples/relay_20/error b/src/test/conf_examples/relay_20/error
new file mode 100644
index 0000000000..e5a81637f8
--- /dev/null
+++ b/src/test/conf_examples/relay_20/error
@@ -0,0 +1 @@
+Unrecognized value in PublishServerDescriptor
diff --git a/src/test/conf_examples/relay_20/error_no_dirauth_relay b/src/test/conf_examples/relay_20/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_20/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_20/torrc b/src/test/conf_examples/relay_20/torrc
new file mode 100644
index 0000000000..87dd74fdc1
--- /dev/null
+++ b/src/test/conf_examples/relay_20/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Invalid PublishServerDescriptor
+ORPort 1
+PublishServerDescriptor bad
diff --git a/src/test/conf_examples/relay_21/error_no_dirauth_relay b/src/test/conf_examples/relay_21/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_21/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_21/expected b/src/test/conf_examples/relay_21/expected
new file mode 100644
index 0000000000..9bcead1402
--- /dev/null
+++ b/src/test/conf_examples/relay_21/expected
@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort 1
+PublishServerDescriptor v1,v2,hidserv
diff --git a/src/test/conf_examples/relay_21/expected_log b/src/test/conf_examples/relay_21/expected_log
new file mode 100644
index 0000000000..ba0d56fb1c
--- /dev/null
+++ b/src/test/conf_examples/relay_21/expected_log
@@ -0,0 +1 @@
+PublishServerDescriptor v1 has no effect
diff --git a/src/test/conf_examples/relay_21/torrc b/src/test/conf_examples/relay_21/torrc
new file mode 100644
index 0000000000..97f032f626
--- /dev/null
+++ b/src/test/conf_examples/relay_21/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Ignored PublishServerDescriptor values
+ORPort 1
+PublishServerDescriptor v1,v2,hidserv
diff --git a/src/test/conf_examples/relay_22/error b/src/test/conf_examples/relay_22/error
new file mode 100644
index 0000000000..c47dd8c4c6
--- /dev/null
+++ b/src/test/conf_examples/relay_22/error
@@ -0,0 +1 @@
+Invalid BridgeDistribution value
diff --git a/src/test/conf_examples/relay_22/error_no_dirauth_relay b/src/test/conf_examples/relay_22/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_22/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_22/torrc b/src/test/conf_examples/relay_22/torrc
new file mode 100644
index 0000000000..e83c83260e
--- /dev/null
+++ b/src/test/conf_examples/relay_22/torrc
@@ -0,0 +1,6 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Bad BridgeDistribution characters
+ORPort 1
+BridgeRelay 1
+BridgeDistribution *$%()@!
diff --git a/src/test/conf_examples/relay_23/error b/src/test/conf_examples/relay_23/error
new file mode 100644
index 0000000000..f76bbe77c4
--- /dev/null
+++ b/src/test/conf_examples/relay_23/error
@@ -0,0 +1 @@
+Relays must use 'auto' for the ConnectionPadding setting
diff --git a/src/test/conf_examples/relay_23/error_no_dirauth_relay b/src/test/conf_examples/relay_23/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_23/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_23/torrc b/src/test/conf_examples/relay_23/torrc
new file mode 100644
index 0000000000..3d28a1e27c
--- /dev/null
+++ b/src/test/conf_examples/relay_23/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Relays can't set ConnectionPadding
+ORPort 1
+ConnectionPadding 1
diff --git a/src/test/conf_examples/relay_24/error b/src/test/conf_examples/relay_24/error
new file mode 100644
index 0000000000..f76bbe77c4
--- /dev/null
+++ b/src/test/conf_examples/relay_24/error
@@ -0,0 +1 @@
+Relays must use 'auto' for the ConnectionPadding setting
diff --git a/src/test/conf_examples/relay_24/error_no_dirauth_relay b/src/test/conf_examples/relay_24/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_24/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_24/torrc b/src/test/conf_examples/relay_24/torrc
new file mode 100644
index 0000000000..1206e59e09
--- /dev/null
+++ b/src/test/conf_examples/relay_24/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Relays can't set ConnectionPadding
+ORPort 1
+ConnectionPadding 0
diff --git a/src/test/conf_examples/relay_25/error b/src/test/conf_examples/relay_25/error
new file mode 100644
index 0000000000..bac681e6cc
--- /dev/null
+++ b/src/test/conf_examples/relay_25/error
@@ -0,0 +1 @@
+Relays cannot set ReducedConnectionPadding
diff --git a/src/test/conf_examples/relay_25/error_no_dirauth_relay b/src/test/conf_examples/relay_25/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_25/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_25/torrc b/src/test/conf_examples/relay_25/torrc
new file mode 100644
index 0000000000..ab862a16f3
--- /dev/null
+++ b/src/test/conf_examples/relay_25/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Relays can't set ReducedConnectionPadding 1
+ORPort 1
+ReducedConnectionPadding 1
diff --git a/src/test/conf_examples/relay_26/error b/src/test/conf_examples/relay_26/error
new file mode 100644
index 0000000000..94334935e3
--- /dev/null
+++ b/src/test/conf_examples/relay_26/error
@@ -0,0 +1 @@
+Relays cannot set CircuitPadding to 0
diff --git a/src/test/conf_examples/relay_26/error_no_dirauth_relay b/src/test/conf_examples/relay_26/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_26/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_26/torrc b/src/test/conf_examples/relay_26/torrc
new file mode 100644
index 0000000000..5dd6d68dc4
--- /dev/null
+++ b/src/test/conf_examples/relay_26/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Relays can't set CircuitPadding to 0
+ORPort 1
+CircuitPadding 0
diff --git a/src/test/conf_examples/relay_27/error b/src/test/conf_examples/relay_27/error
new file mode 100644
index 0000000000..e26ce46914
--- /dev/null
+++ b/src/test/conf_examples/relay_27/error
@@ -0,0 +1 @@
+Relays cannot set ReducedCircuitPadding
diff --git a/src/test/conf_examples/relay_27/error_no_dirauth_relay b/src/test/conf_examples/relay_27/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_27/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_27/torrc b/src/test/conf_examples/relay_27/torrc
new file mode 100644
index 0000000000..8556b2f351
--- /dev/null
+++ b/src/test/conf_examples/relay_27/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Relays can't set ReducedCircuitPadding 1
+ORPort 1
+ReducedCircuitPadding 1
diff --git a/src/test/conf_examples/relay_28/error b/src/test/conf_examples/relay_28/error
new file mode 100644
index 0000000000..3f14df975b
--- /dev/null
+++ b/src/test/conf_examples/relay_28/error
@@ -0,0 +1 @@
+SigningKeyLifetime is too short
diff --git a/src/test/conf_examples/relay_28/error_no_dirauth_relay b/src/test/conf_examples/relay_28/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_28/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_28/torrc b/src/test/conf_examples/relay_28/torrc
new file mode 100644
index 0000000000..3e2c895bb7
--- /dev/null
+++ b/src/test/conf_examples/relay_28/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# Short key lifetimes
+ORPort 1
+SigningKeyLifetime 1
diff --git a/src/test/conf_examples/relay_29/error_no_dirauth_relay b/src/test/conf_examples/relay_29/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_29/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_29/expected b/src/test/conf_examples/relay_29/expected
new file mode 100644
index 0000000000..1d25374ed1
--- /dev/null
+++ b/src/test/conf_examples/relay_29/expected
@@ -0,0 +1,2 @@
+Nickname Unnamed
+ORPort 1
diff --git a/src/test/conf_examples/relay_29/expected_log b/src/test/conf_examples/relay_29/expected_log
new file mode 100644
index 0000000000..f46c609c0c
--- /dev/null
+++ b/src/test/conf_examples/relay_29/expected_log
@@ -0,0 +1 @@
+Linelist option 'MyFamily' has no value\. Skipping
diff --git a/src/test/conf_examples/relay_29/torrc b/src/test/conf_examples/relay_29/torrc
new file mode 100644
index 0000000000..4181d5acc2
--- /dev/null
+++ b/src/test/conf_examples/relay_29/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# Options from relay/relay_config.c
+# MyFamily normalisation: empty MyFamily
+ORPort 1
+MyFamily
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/conf_examples/relpath_rad/error b/src/test/conf_examples/relpath_rad/error
new file mode 100644
index 0000000000..e131744475
--- /dev/null
+++ b/src/test/conf_examples/relpath_rad/error
@@ -0,0 +1 @@
+RunAsDaemon is not compatible with relative paths.
diff --git a/src/test/conf_examples/relpath_rad/torrc b/src/test/conf_examples/relpath_rad/torrc
new file mode 100644
index 0000000000..fe02441c3f
--- /dev/null
+++ b/src/test/conf_examples/relpath_rad/torrc
@@ -0,0 +1,4 @@
+
+# Relative-path data directories are incompatible with RunAsDaemon
+DataDirectory ./datadir
+RunAsDaemon 1
diff --git a/src/test/conf_failures/README b/src/test/conf_failures/README
new file mode 100644
index 0000000000..0da470eeb4
--- /dev/null
+++ b/src/test/conf_failures/README
@@ -0,0 +1,5 @@
+This directory contains typical test_parseconf.sh failure cases.
+
+If these directories are copied into conf_examples, test_parseconf.sh will
+fail. Use these failure cases to make sure test_parseconf.sh handles failures
+correctly, and produces useful output.
diff --git a/src/test/conf_failures/fail-error-success/error b/src/test/conf_failures/fail-error-success/error
new file mode 100644
index 0000000000..569a631e86
--- /dev/null
+++ b/src/test/conf_failures/fail-error-success/error
@@ -0,0 +1 @@
+Tor
diff --git a/src/test/conf_failures/fail-error-success/torrc b/src/test/conf_failures/fail-error-success/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_failures/fail-error-success/torrc
diff --git a/src/test/conf_failures/fail-error/error b/src/test/conf_failures/fail-error/error
new file mode 100644
index 0000000000..4c0be97832
--- /dev/null
+++ b/src/test/conf_failures/fail-error/error
@@ -0,0 +1 @@
+no match
diff --git a/src/test/conf_failures/fail-error/torrc b/src/test/conf_failures/fail-error/torrc
new file mode 100644
index 0000000000..bb6fe186a4
--- /dev/null
+++ b/src/test/conf_failures/fail-error/torrc
@@ -0,0 +1 @@
+bad bad bad
diff --git a/src/test/conf_failures/fail-expected-error/expected b/src/test/conf_failures/fail-expected-error/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_failures/fail-expected-error/expected
diff --git a/src/test/conf_failures/fail-expected-error/torrc b/src/test/conf_failures/fail-expected-error/torrc
new file mode 100644
index 0000000000..bb6fe186a4
--- /dev/null
+++ b/src/test/conf_failures/fail-expected-error/torrc
@@ -0,0 +1 @@
+bad bad bad
diff --git a/src/test/conf_failures/fail-expected-log/expected b/src/test/conf_failures/fail-expected-log/expected
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_failures/fail-expected-log/expected
diff --git a/src/test/conf_failures/fail-expected-log/expected_log b/src/test/conf_failures/fail-expected-log/expected_log
new file mode 100644
index 0000000000..bb6fe186a4
--- /dev/null
+++ b/src/test/conf_failures/fail-expected-log/expected_log
@@ -0,0 +1 @@
+bad bad bad
diff --git a/src/test/conf_failures/fail-expected-log/torrc b/src/test/conf_failures/fail-expected-log/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_failures/fail-expected-log/torrc
diff --git a/src/test/conf_failures/fail-expected/expected b/src/test/conf_failures/fail-expected/expected
new file mode 100644
index 0000000000..67be85f127
--- /dev/null
+++ b/src/test/conf_failures/fail-expected/expected
@@ -0,0 +1 @@
+bad
diff --git a/src/test/conf_failures/fail-expected/torrc b/src/test/conf_failures/fail-expected/torrc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/test/conf_failures/fail-expected/torrc
diff --git a/src/test/ed25519_exts_ref.py b/src/test/ed25519_exts_ref.py
index 75562184b5..dcc0a7c25a 100644
--- a/src/test/ed25519_exts_ref.py
+++ b/src/test/ed25519_exts_ref.py
@@ -8,6 +8,11 @@
Includes self-tester and test vector generator.
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import slow_ed25519
from slow_ed25519 import *
@@ -48,7 +53,7 @@ def blindPK(pk, param):
def expandSK(sk):
h = H(sk)
a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
- k = ''.join([h[i] for i in range(b/8,b/4)])
+ k = bytes(h[i] for i in range(b//8,b//4))
assert len(k) == 32
return encodeint(a)+k
@@ -59,7 +64,7 @@ def publickeyFromESK(h):
def signatureWithESK(m,h,pk):
a = decodeint(h[:32])
- r = Hint(''.join([h[i] for i in range(b/8,b/4)]) + m)
+ r = Hint(bytes([h[i] for i in range(b//8,b//4)]) + m)
R = scalarmult(B,r)
S = (r + Hint(encodepoint(R) + pk + m) * a) % l
return encodepoint(R) + encodeint(S)
@@ -147,7 +152,7 @@ class SelfTest(unittest.TestCase):
# Check that identities match
assert(identity == identity2)
# Check that identity is the point (0,1)
- assert(identity == [0L,1L])
+ assert(identity == [0,1])
# Check identity element: a*E = E, where a is a random scalar
scalar = random_scalar(os.urandom)
@@ -181,22 +186,22 @@ BLINDING_PARAMS = [
PREFIX = "ED25519_"
def writeArray(name, array):
- print "static const char *{prefix}{name}[] = {{".format(
- prefix=PREFIX,name=name)
+ print("static const char *{prefix}{name}[] = {{".format(
+ prefix=PREFIX,name=name))
for a in array:
h = binascii.b2a_hex(a)
if len(h) > 70:
h1 = h[:70]
h2 = h[70:]
- print ' "{0}"\n "{1}",'.format(h1,h2)
+ print(' "{0}"\n "{1}",'.format(h1,h2))
else:
- print ' "{0}",'.format(h)
- print "};\n"
+ print(' "{0}",'.format(h))
+ print("};\n")
def comment(text, initial="/**"):
- print initial
- print textwrap.fill(text,initial_indent=" * ",subsequent_indent=" * ")
- print " */"
+ print(initial)
+ print(textwrap.fill(text,initial_indent=" * ",subsequent_indent=" * "))
+ print(" */")
def makeTestVectors():
comment("""Test vectors for our ed25519 implementation and related
@@ -252,11 +257,9 @@ def makeTestVectors():
if __name__ == '__main__':
import sys
if len(sys.argv) == 1 or sys.argv[1] not in ("SelfTest", "MakeVectors"):
- print "You should specify one of 'SelfTest' or 'MakeVectors'"
+ print("You should specify one of 'SelfTest' or 'MakeVectors'")
sys.exit(1)
if sys.argv[1] == 'SelfTest':
unittest.main()
else:
makeTestVectors()
-
-
diff --git a/src/test/example_extrainfo.inc b/src/test/example_extrainfo.inc
index 0bf2341ef5..94708e6812 100644
--- a/src/test/example_extrainfo.inc
+++ b/src/test/example_extrainfo.inc
@@ -1,25 +1,42 @@
+/* These entries are automatically generated by makedesc.py to make sure
+ * that their keys and signatures are right except when otherwise
+ * specified. */
+
static const char EX_EI_MINIMAL[] =
- "extra-info bob 3E1B2DC141F2B7C6A0F3C4ED9A14A9C35762E24B\n"
- "published 2014-10-05 20:07:00\n"
+ "extra-info HomersRelay 3390094906366A15D5CD78550424FAD141CF1067\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstTAd17tFTNejNRgbv721EkIcbFOsiQYWMvXPIwupcMVOSRAQAgBABG7Eha\n"
+ "cQElmfndkTBiOJBk18P4nP6BtRWGhYEz9th4chXWqOuA+/8IfLPYb39YuFUOadAE\n"
+ "cgKPEa14EHB7K5QbGToAm91E0H5kVX6A9GDAc7QKKMYLGO4Tcu2WntzSmgY=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2020-10-14 20:58:04\n"
+ "router-sig-ed25519 3c5gw2tHzcjS0zKSdZrL2Mx3pdEe2j8Gc62nQWKl8m2DLhWqrTz9dC6LimoiipWuV0Xo8tT2f/fStMBGbayRAQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "K5GAkVjpUlofL78NIOE1VDxFn8yYbHK50rVuZG2HxqG/727bon+uMprv4MHjfDcP\n"
- "V3l9u1uUdGiUPOl8j+hRNw4z/ODeCj/24r2+L32MTjyfUhK49Ld2IlK9iZKlgKYi\n"
- "zyoatxdAjU8Xc5WPX692HO4/R9CGLsUfYcEEFU2R3EA=\n"
+ "tcFC3oRyHAaZTQn0g5G5rsjq3CI9Ky/GlhIQz1G5VWczjTXIb0fGGyerraq5HW7v\n"
+ "UEDQrA3dYjuFB3ACyKesoR9HbMSVOPSHkge4WWtlm9XoPzgU6IGWPhlnWjYC9ozV\n"
+ "2m8J8Gx+3IUy4xWWIDOXLV0Wlp6PWwXbYHWllHQLjKM=\n"
"-----END SIGNATURE-----\n"
;
-
-static const char EX_EI_MINIMAL_FP[] = "3E1B2DC141F2B7C6A0F3C4ED9A14A9C35762E24B";
+ATTR_UNUSED static const char EX_EI_MINIMAL_FP[] = "3390094906366A15D5CD78550424FAD141CF1067";
+ATTR_UNUSED
static const char EX_EI_MINIMAL_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALSppIF3t3wOAm4fzxRvK+q/wh1gGAWwS0JEn8d+c/x+rt1oQabGkqsB\n"
- "GU6rz1z1AN02W0P2+EcyJQVBjGR3gHQNoDGx0KIdnr3caGAw3XmQXrJLPaViEk28\n"
- "RJMxx6umpP27YKSyEMHgVTDXblKImT0mE7fVOx8tD0EWRYazmp4NAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n";
-
+ "MIGJAoGBANNVP8AEuktLfk1QmK5SYrfPF9KBxub5dubqaPGMGEHwtOpR8Mo8ZfKZ\n"
+ "bi3nmpO273uVZDz0toqgcI9v87x6v/2ZPaksRcFXl2vVdJ2L8R51yvr6EjhatEi/\n"
+ "ntPRQ67oSEA9sqeI4R1NRcrfEpzLyBOGZ/SHsctGX+9edZGZVpkrAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
static const char EX_EI_MAXIMAL[] =
- "extra-info bob FF8248FE780A7236D3FA5D62DEA642055135F942\n"
- "published 2014-10-05 20:07:00\n"
+ "extra-info HomersRelay 7369E5BE5E183609D08A766F6FF36F9F5DE2AD32\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstTAY8EcZ8LbMYKiBCrVu1KMM1b0nM5amNOdjzblJezWiJSAQAgBABdtyfT\n"
+ "YOvrB4cdPm0k7IoyXzVi3qYFtr82nshImKJ/tGO8H7DhU7s+7lsOKInn4RVaUS1/\n"
+ "r2Z05Qb7lj9q/jhVnruoiG/N6Ii0rjWuRZmmR7sZdCpAGzJoRx0hO1vshAU=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2020-10-14 20:58:04\n"
"opt foobarbaz\n"
"read-history 900 1,2,3\n"
"write-history 900 1,2,3\n"
@@ -46,390 +63,322 @@ static const char EX_EI_MAXIMAL[] =
"exit-kibibytes-written FOO\n"
"exit-kibibytes-read FOO\n"
"exit-streams-opened FOO\n"
+ "router-sig-ed25519 JKJB3EvFZUOff5RgwgSowwTB/TP6VB+IbbeqGPA0Mp9ft9KiulgCuoWqGiUdu/1Zm02dSdYWIlKNf2AijTy0Cg\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "ZO79bLlWVNIruCnWW9duDcOKydPWbL5DfrpUv5IRLF4MMFoacMUdJPDUs9e+wY2C\n"
- "zndHe6i2JK7yKJj+uCOSC8cx61OLG+kVxMLJ/qhA4H5thrYb+GpzMKwbHzQc3PTH\n"
- "zHRzj041iWXTL7/DMaQlpJOBoac/wTSIKzoV2B00jBw=\n"
+ "rk8hYNILFc+Ka3a8vyVg3O4Qs5++ih5KmCP1f/onm++fUM/kGCA13KP3hF0conRH\n"
+ "bTdDas6PJALVgNq1bWsCbuqtz2eIf8r22+gE5nRuahh5u0JLzJzEXeZo/jpHQDAM\n"
+ "ZbMqs2SOKQk8QmGyUa+ul89FR9El0mBE8dMPwYnWl14=\n"
"-----END SIGNATURE-----\n"
;
-
-static const char EX_EI_MAXIMAL_FP[] = "FF8248FE780A7236D3FA5D62DEA642055135F942";
+ATTR_UNUSED static const char EX_EI_MAXIMAL_FP[] = "7369E5BE5E183609D08A766F6FF36F9F5DE2AD32";
+ATTR_UNUSED
static const char EX_EI_MAXIMAL_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANSpkYhHUW1EqodY4d3JRbvEM1vjjR/vEE8gjONiJ5t2Sten53jzt8bh\n"
- "8/VJn7pQGs8zR5CIxCw4P68xMtZJJedS3hhjqubheOE/yW1DtpkiCf+zVEaLpeA8\n"
- "fYQChkRICnR/BZd4W9bbohLVII5ym2PaJt2ihB3FeVZIsGXm4wxhAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n";
-
+ "MIGJAoGBAMJ9qPjQ0i7LGsRDIBJw+gMZLx1rYNCmu0KPSf7BixQP1Tk7u8TVL+/O\n"
+ "jmzOP8L2etdsl5ousnDjulXbxF3wn5pU1+d35XxkfUbcuYzKc90SwYsXp0HOdH0q\n"
+ "XdKofHK0TyTfWknBp9JId1r6lmjR2Sk+o88yES05NS95evaRkX2/AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
static const char EX_EI_BAD_SIG1[] =
- "extra-info bob 3E1B2DC141F2B7C6A0F3C4ED9A14A9C35762E24B\n"
- "published 2014-10-05 20:07:00\n"
+ "extra-info HomersRelay 2F6C040BC5154D4A0F5BDFC1D6560EBD33B735C7\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstTAQhl8HDHWPB6RgLDaVIHfzcJ0CKg6wZINNChtW8QyAacAQAgBAA0yzGH\n"
+ "Ny+LC1czePmvy4QZMKgiyWIhrqqtT5cYgTnnF+oBcVpKEYkEvl/z2/bOTcIFW46U\n"
+ "wqGWJkQxqMbrxYKRo3dspN5Z7E1E8inkI3+oAv2rn4Xj+ZG7lWTwwuw97wc=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2020-10-14 20:58:04\n"
+ "router-sig-ed25519 1O2wsG/FhFdr117eNcqlB0RSJy5G4ExPCSAS8VG5yDirv6SepYLn99ppqGDH80WtOTc1+LzwZYkQ8tyko1vYAw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "K5GAkVjpUlofL78NIOE1VDxFn8yYbHK50rVuZG2HxqG/727bon+uMprv4MHjfDcP\n"
"V3l9u1uUdGiUPOl8j+hXXw4z/ODeCj/24r2+L32MTjyfUhK49Ld2IlK9iZKlgKYi\n"
"zyoatxdAjU8Xc5WPX692HO4/R9CGLsUfYcEEFU2R3EA=\n"
"-----END SIGNATURE-----\n"
;
-
-static const char EX_EI_BAD_SIG2[] =
- "extra-info bob 3E1B2DC141F2B7C6A0F3C4ED9A14A9C35762E24B\n"
- "published 2014-10-06 20:07:00\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "K5GAkVjpUlofL78NIOE1VDxFn8yYbHK50rVuZG2HxqG/727bon+uMprv4MHjfDcP\n"
- "V3l9u1uUdGiUPOl8j+hRNw4z/ODeCj/24r2+L32MTjyfUhK49Ld2IlK9iZKlgKYi\n"
- "zyoatxdAjU8Xc5WPX692HO4/R9CGLsUfYcEEFU2R3EA=\n"
- "-----END SIGNATURE-----\n"
- ;
-
-static const char EX_EI_BAD_SIG3[] =
- "extra-info bob 3E1B2DC141F2B7C6A0F3C4ED9A14A9C35762E24B\n"
- "published 2014-10-05 20:07:00\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "K5GAkVjpUlofL78NIOE1VDxFn8yYbHK50rVuZG2HxqG/727bon+uMprv4MHjfDcP\n"
- "V3l9u1uUdGiUPOl8j+hRNw4z/ODeCj/24r2+L32MTjyfUhK49Ld2IlK9iZKlgKYi\n"
- "zyoatxdAjU8Xc5WPX692HO4/R9CGLsUfYcEEFU2=\n"
- "-----END SIGNATURE-----\n"
+ATTR_UNUSED static const char EX_EI_BAD_SIG1_FP[] = "2F6C040BC5154D4A0F5BDFC1D6560EBD33B735C7";
+ATTR_UNUSED
+static const char EX_EI_BAD_SIG1_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKN5UTDCnsKYmUa2kORmJZUbpNv+dn66Fy4tj3x4rwFHKp7MOlgwK0Zj\n"
+ "C4dh77PUXRvnqM0yb3hDCiVJ9XsMbql8JCO8KrMoCoBvKXCVud30/gCY7G0Nf+Py\n"
+ "Z8j1NnOmKLuXnvX5saLtFKLEgAGMf/JTUExWmTAWKk0Ax9rQjVtVAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
;
-
-static const char EX_EI_BAD_FP[] =
- "extra-info bob C34293303F0F1E42CB14E593717B834E8E53797D8888\n"
- "published 2014-10-05 20:07:00\n"
+static const char EX_EI_BAD_SIG2[] =
+ "extra-info HomersRelay 292CB24DC90BEB8210E33B54F63271ED4034ABF9\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstTAS/RMEB+g3lPq9f9/tSb67KQWzKS1B8ujutOZv0byqpyAQAgBABZsEqr\n"
+ "UbN2SrNDRAIWkC7EL8hpUJOCbIRYKRuQ9HQFDrIM8ZI7h542JOKJexNOQmiZA5Ut\n"
+ "cWa/cJvraK48DChLlOZq62S2fNpX43pTktDVV6WqGp/P8IJwT+l6zBqFZQQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2020-10-14 20:58:04\n"
+ "router-sig-ed25519 XFBQj7H4bitpx5Bq9c0Od7dO4qiZKDHbeLGeV4FP+SsGfpft2VvY8/V0oHx2z2Sl3938MIfNxQMjBQ+EtHrdYDA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "IDA8ryUYeMx7+Au/xQmX7Y8fXksoHUOXmePND2JYM4rPfishQJ1LpQ15KrolOZDH\n"
- "FVIk3RmCefNlJeS1/UgWPcU8u2nGw1YQuRBHF4ViTmZ0OevI1pTsSApl4+oIx2dy\n"
- "DGgCQmKfMbaOixIK8Ioh1Z2NUfMkjbUUE2WWgFTAsac=\n"
+ "sb8tYPSeSmaTEUpu7v374PVPEoYqTbIpaHezqbC/PfldVenXRLkoB893hP72IJQZ\n"
+ "ru9go6Kc6LuobMuVtpwey8nsPqhu8WZn3E4pSL8lCXosttvxtZnDD7/Fu6Ddj05A\n"
+ "ehZpDi2oyBVdR0b5JI7a+m6/j5snn0TTjbGmHHnDPY0=\n"
"-----END SIGNATURE-----\n"
;
-
-static const char EX_EI_BAD_FP_FP[] = "C34293303F0F1E42CB14E593717B834E8E53797D";
-static const char EX_EI_BAD_FP_KEY[] =
+ATTR_UNUSED static const char EX_EI_BAD_SIG2_FP[] = "292CB24DC90BEB8210E33B54F63271ED4034ABF9";
+ATTR_UNUSED
+static const char EX_EI_BAD_SIG2_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKXMSbif4fG+BW/5lIq5V1tMRondIUfKiNizp0E6EcBw5LvYfQV6zrj8\n"
- "HmMFbB/WGf9XGVMxIBzxzeQBRvCQJh+0QH7+ju5/isIHJZsACMILepr6ywmCcjVU\n"
- "iYRtC8zGQLqfkf2cNoo7AhcI5i/YzyW2u1zmbPX5J+8sUErfxydbAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n";
-
+ "MIGJAoGBAM3PF/tml0dOEm53J54liJStfBBlK8cgYhApmm9NMDxqK1DssZBIL4v7\n"
+ "6KTx4yTr9U/rIBHF/0rISy9l86J38eT4twFxuIGcFtGSEFnUgp21uVysev+svQdW\n"
+ "s+RrFLkPu0Wus9v72f7QeAdFA2GKQmZnybsvRhLiGfomQls062wDAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
static const char EX_EI_BAD_NICKNAME[] =
- "extra-info bobhasaverylongnameandidontthinkweshouldlethim A4EA2389A52459B3F7C7121A46012F098BDFC2A4\n"
- "published 2014-10-05 20:07:00\n"
+ "extra-info bobhasaverylongnameandidontthinkweshouldlethim AB6C1ABB2A8F6D48ABE641912C8829F686BC6A9D\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstTAdi62xiknL6gvZDhCF37r7jL281WUDop4iImEX8bTeSYAQAgBAAfBLo2\n"
+ "i4Yuo3t/HGACeJZoHvVww8HTJq4NyDH5HBdU594t+qpdy/3rlQDsZFxTdh6nYV27\n"
+ "F6aZ6ZkgUSKW//XfX9Vn2xCSGhhwM2kkbWPQCelHAeVUwkCmScz4/rWo0wg=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2020-10-14 20:58:04\n"
+ "router-sig-ed25519 2YBjWS4B6+ZmLDt7DXxyckF/RgAu9PnaVgpJQTEbrogAjyeoiOplwzx86nc1YtxggCde1KsqicqsYENa+kgiCA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "e2wLJFThRMGawxKrQPuH2XCLek/LJsg4XOB8waAjE0xdHOrzjur9x1jIxy7DVU6t\n"
- "z1edbIoL24qucMJvFy2xjSQhFRX4OsyNc0nWr3LfJnTW9aEmxuwXM+mltUD2uFN1\n"
- "2vYOIQjUmJwS2yfeSKnhXEl2PWVUmgzYL3r4S5kHco4=\n"
+ "YiYQB9RBEDxJf729Qgil/pzRqKNR5hsvTD3ODN2IcF/hbwKTtjURCTQYBDXAIB1q\n"
+ "mRpS1R+Rxcp6ta2kfKv5xeuDTcoYcCLeee6Cwivq8/JHhoqQcndG+2Bh8WUGPrRN\n"
+ "8X2AKAVVy/OF+/AZmTAhvWqYfJEZ9HaKEj+k8Ot/u5w=\n"
"-----END SIGNATURE-----\n"
;
-
-static const char EX_EI_BAD_NICKNAME_FP[] = "A4EA2389A52459B3F7C7121A46012F098BDFC2A4";
+ATTR_UNUSED static const char EX_EI_BAD_NICKNAME_FP[] = "AB6C1ABB2A8F6D48ABE641912C8829F686BC6A9D";
+ATTR_UNUSED
static const char EX_EI_BAD_NICKNAME_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKfq7oxD1kMu1+zeG2UVXN4vOu6FDp0V/olA3ttmXpUCgCiBxWTgtwNl\n"
- "nPf0HcKMaCp/0D9XrbhvIoOsg0OTf1TcJfGsA/zPG7jrWYa4xhD50KYvty9EINK9\n"
- "/UBWNSyXCFDMqnddb/LZ8+VgttmxfYkpeRzSSmDijN3RbOvYJhhBAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n";
-
+ "MIGJAoGBAMhug5Yec6r7TIViU3V4BeGGIckfWDVS1ewrhWe/mK5JP2jWZ8JJov7v\n"
+ "Wc2WArhMWYm8idmA+QwFKMmywdfkwc4jHu2jTcIFxTxl2zjFddThSgMgIGXtaBwc\n"
+ "Rn4kuIAG8PekuNNL903rol5OakE6EUvLmJcMYB3rO4W8C6oMhvalAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
static const char EX_EI_BAD_TOKENS[] =
- "extra-info bob 6F314FB01A31162BD5E473D4977AC570DC5B86BB\n"
- "published 2014-10-05 20:07:00\n"
- "published 2014-10-05 20:07:00\n"
+ "extra-info HomersRelay 50AF9F6CE4107055260137181DEA24095D292F81\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstTAfELNKA/8+s09sVWDRCVk0hfX3+ysqp2vFE6atiPZ4hGAQAgBADVXm9g\n"
+ "BXoEjAjHvPwNPaZmrtjYTIc4ssiqud7/XKN1R1Ys+yJuZv23pJrGktXHiNBPI3UX\n"
+ "JOfbtNtw8depsxsDa232u1ZSLWCQ6LtaoalyT/mqs47ASSyYwcvgauWPYQY=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2020-10-14 20:58:04\n"
+ "published 2020-10-14 20:58:04\n"
+ "router-sig-ed25519 8ggCNPsFzbfbILBVpiKRlUqEaATq5F17Xo+5op/aoPPhp0pCmucYpl0aGX0hbJCGAOjShBmX362ARmpBBDoADQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "lhRIafrkKoQmnUoBLiq4XC8XKXrleGJZ5vefkLcgjOJ5IffsvVdIA7Vqq/ISbPrG\n"
- "b/Zs0sJNL6naHPxJBglgHJqksSyiYHaeOetXg2Rb+vZ1v2S5BrVgk1nPMDhyIzqc\n"
- "zU7eCxFf/1sXKtWlEKxGdX4LmVfnIln5aI31Bc4xRrE=\n"
+ "LW/DIzbGzTmvvr/wKQo41utHqwAbHvrtF/X4wCQ0Db4GDHgDlac2gtzhz++X8Rrh\n"
+ "fiLBdby4omYP/uPkk9pTwvNaSHpsE17zCWrg6re7lUfgq/mJ7VB8eRGzd8NIELEQ\n"
+ "gBK/DQ9oF4yHHRTbNRusUBwtU/UB8wNdkvTYAVw9VWw=\n"
"-----END SIGNATURE-----\n"
;
-
-static const char EX_EI_BAD_TOKENS_FP[] =
- "6F314FB01A31162BD5E473D4977AC570DC5B86BB";
+ATTR_UNUSED static const char EX_EI_BAD_TOKENS_FP[] = "50AF9F6CE4107055260137181DEA24095D292F81";
+ATTR_UNUSED
static const char EX_EI_BAD_TOKENS_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAL7Z8tz45Tb4tnEFS2sAyjubBV/giSfZdmXRkDV8Jo4xqWqhWFJn7+zN\n"
- "AXBWBThGeVH2WXrpz5seNJXgZJPxMTMsrnSCGcRXZw0Npti2MkLuQ6+prZa+OPwE\n"
- "OyC6jivtAaY/o9iYQjDC2avLXD3N4LvoygyF418KnNcjbzuFygffAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n";
-
+ "MIGJAoGBAMOlFKzgAdxLVePfB0epCUtq3v4vVptYdQNLpqtjhNVZaNwrYKcyO6Wd\n"
+ "115iHgAwbeh7Eva0qb/S3F1KKspiCoTNC2O54Yn8i3kIWfWXjDsdWEJ/CtOZumwH\n"
+ "DbcAQuczG0D8nTxxn42+QaoHFzTMo1sJ2c91qY7OV7kWYqMB++2VAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
static const char EX_EI_BAD_START[] =
- "published 2014-10-05 20:07:00\n"
- "extra-info bob 5CCCACE71A9BDB5E8E0C942AB3407452350434C0\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstTAT5Axv+qhd0NtmmMe+AXThBG1h3cs559MPKDxbV5Y5TzAQAgBABOa2zh\n"
+ "7y8bgCx3/uQCJ+v9kxNGZDQu+soUPbXyd7OZEaUE/2S7+YtdmqEtQNaF5T+MfEe8\n"
+ "6zDRnfXeNQaQSVGM2mhrkvWGYJkKecOQzuBsnlUmicLqyDV3HY9iefo8Two=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2020-10-14 20:58:04\n"
+ "router-sig-ed25519 Q3p7pd9YoXRgrRJN9dVqmR382KLxsGQu0zBr0JrfFaqow2fmTwXHnKYJZb5SzQeeYIjnHG/uSRWMmAcQoHnrBw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "BOiWgexqCAMZ8uyJ7jwBwRkz7Ox8cT4BImkmkV3bQiZgcWvPiYA3EnCm2ye48Ldg\n"
- "zBST2p6zJM5o4MEDYGMxfViS86Abj/z7DOY1gtLhjmAaVjIIpXc3koxEZtzCecqy\n"
- "JQz6xEg9/KoEuoT0DRrfYQ+KtQfzBDWrotfOvEa1rvc=\n"
+ "mk0iHF8QMUfJUCjFWXihHQQjFflulpFDYeBgvCwUqrnIlbufuzLdoKEnrio0HCMq\n"
+ "VcJ+84iAW0likR4qflmerDobhbEpeA21pZx1zCkLdi4KzV1u79xvY5qHKHxWBbeY\n"
+ "W8yDErz6jVoGEqGOlg9Whlo6QSukttdKK974ugebVTw=\n"
"-----END SIGNATURE-----\n"
;
-
-static const char EX_EI_BAD_START_FP[] = "5CCCACE71A9BDB5E8E0C942AB3407452350434C0";
+ATTR_UNUSED static const char EX_EI_BAD_START_FP[] = "0B6D931123DA9B41F901D6EFCCD64CFBB89C6010";
+ATTR_UNUSED
static const char EX_EI_BAD_START_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAK2OCIfM6Cin/lq99Z3w9tl6HeyGlkBZu9MQEPHxqGIHTq78lIC1UkrC\n"
- "6NTqlrHBV9dmfzdwJn4GgMWsCZafL0FPIH3HNyNKUxLgyjixyKljHx2rfErSfOxI\n"
- "bMoOGBKv7m1EZZ0O5uG9ly9MBiNGdJyLdlnVvH7wSCnYciizpO4lAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n";
-
-static const char EX_EI_BAD_PUBLISHED[] =
- "extra-info bob E67C477E3536BDE348BD407426D9679E5AE0BC16\n"
- "published 2014-99-05 20:07:00\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "l45IziBaXRKIjPAIUogMFNjQgH6k6Vm0+6r5+oByr4sP+B3ufNdUA6+WqBs43F0Z\n"
- "IqcJiT9nFn0DuNd/liOyOCixppDLx5h5NrhoGqcT3ySADEEXhzjlmc35TI3YBNVO\n"
- "v98fotmwIEg9YRWVGPg6XuIn2PRyiboFyjUpaYGCV0Q=\n"
- "-----END SIGNATURE-----\n"
+ "MIGJAoGBAMfN4ZtcZcKFtmMakKEghsW4SWYPlxg5DTtSD3OSbarO0mucpQqsQnkx\n"
+ "Nr4yFOGHmJiZxkKbqVwAq78ZUfFzWVW+I2TaPCWKvCdEib6SlMXueufgcsW2eQLz\n"
+ "URbswEArwivNzY2wcnweGI6fdoN1FZloE1pk6YR9aZLI91RaWhHNAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
;
-
-static const char EX_EI_BAD_PUBLISHED_FP[] = "E67C477E3536BDE348BD407426D9679E5AE0BC16";
-static const char EX_EI_BAD_PUBLISHED_KEY[] =
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAL7q8GEI18iv8Fo0QbNHmFatQ2FNacalPldpmKUdMJYEVZtdOR0nhcrY\n"
- "BvG6303md3INygg+KP49RvWEJR/cU4RZ9QfHpORxH2OocMyRedw2rLex2E7jNNSi\n"
- "52yd1sHFYI8ZQ4aff+ZHUjJUGKRyqpbc8okVbq/Rl7vug0dd12eHAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n";
-
-static const char EX_EI_GOOD_ED_EI[] =
- "extra-info emma A692FE045C32B5E3A54B52882EF678A9DAC46A73\n"
+static const char EX_EI_BAD_PUBLISHED[] =
+ "extra-info HomersRelay 94C608B2CB50E5D488D345A0F54D1C78D13C69E1\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AYgHn/OKR8GHBlscN5VkO73wA9jSci8QgTM30615ZT44AQAgBAC08woT\n"
- "MBZpKzRcaoEJhEG7+RmuYtnB2+nODk9IRIs8ZoyYPTZ6dLzI+MLMmtzUuo/Wmvw0\n"
- "PflTyCb2RlWitOEhAErWH3Z9UmYGnzM/COId0Fe3ScSriyvRoFnJY1+GVAQ=\n"
+ "AQQABstTAUUzHVvllaO8HwZE3nF9kV7fqSK3WzuS3GvWRF69YHJ3AQAgBACUuECr\n"
+ "PwY0R1fw7rzTgcYuoWCeHhAbePuO6SNk39cQYsI26HPCQakL3yK4258tXsxC4LGN\n"
+ "DzH21SnS5gopeyg17C3ME6LtV1AAUz3Ytmf+2iNHIEJG9FHruZUeX7vCmA0=\n"
"-----END ED25519 CERT-----\n"
- "published 2014-10-05 20:07:00\n"
- "router-sig-ed25519 a7K8nwfg+HrdlSGQwr9rnLBq0qozkyZZs6d6aiLEiXGdhV1r9KJncmlQ5SNoY/zMQlyQm8EV5rCyBiVliKQ1Bw\n"
+ "published 2020-99-14 20:58:04\n"
+ "router-sig-ed25519 9AtZy5azhX81mxtY/ujFfZvoR3biUDtkZnnFMMLg25A2zmjou6WAQeoRQkPH/lN7sBN68NSiJ9+qF2Ef9m+qCQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "GvmCmIGgbC1DeawRyRuChy62VmBOG0EviryG/a2qSZiFy0iPPwqSp5ZyZDQEIEId\n"
- "kkk1zPzK1+S3fmgOAXyXGH0r4YFkoLGnhMk07BoEwi6HEXzjJsabmcNkOHfaOWgs\n"
- "/5nvnLfcmxL4c6FstZ7t9VQpE06y3GU0zwBeIy1qjp0=\n"
+ "eBc/YKRfl2OLethfPnK+rp6WF4Q//dCEI63eYMesUuLomAiOWdvPjW8Ispl9auPx\n"
+ "DLw5BQR4bYuO2oTNWS0fGyh7sykepCkuuvfcxRMDuGDGz9KmfJezKOiHgPENpzD+\n"
+ "hlTqtTKRwD1TP3hJtHSxYi8ZTR9XuR0MuZ/uQxVSwW8=\n"
"-----END SIGNATURE-----\n"
- "\n"
- "\n"
;
-static const char EX_EI_GOOD_ED_EI_FP[] =
- "A692FE045C32B5E3A54B52882EF678A9DAC46A73";
-static const char EX_EI_GOOD_ED_EI_KEY[] =
+ATTR_UNUSED static const char EX_EI_BAD_PUBLISHED_FP[] = "94C608B2CB50E5D488D345A0F54D1C78D13C69E1";
+ATTR_UNUSED
+static const char EX_EI_BAD_PUBLISHED_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAM3jdYwjwGxDWYj/vyFkQT7RgeCNIn89Ei6D2+L/fdtFnqrMXOreFFHL\n"
- "C7CK2v2uN3v+uXxfb5lADz3NcalxJrCfGTGtaBk7PwMZraTSh2luFKOvSRBQCmB1\n"
- "yD5N0QqnIhBJoGr6NITpbWyiTKWvYLjl9PZd9af8e8jQCAa5P1j1AgMBAAE=\n"
+ "MIGJAoGBALSDc0v0jfhvfcx7rxGQhCGzBGPZepZoJQY/dQrjBlMo0EqZg3KjYXiv\n"
+ "JpukXfXMgbiTyTv2Kknsbhjx1WhVTwNs+smdea6RryQJX/PbO7HzriaCm99XFO/b\n"
+ "IlJ918osvoU1VIhiPTzTJPUT6hmP4RNHXJe2ZTjDACGa/Kk16SLlAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
;
-
static const char EX_EI_ED_MISSING_SIG[] =
- "extra-info rachel 2A7521497B91A8437021515308A47491164EDBA1\n"
+ "extra-info HomersRelay 961B50E8433A0ECDAFFB51FBC951B869BD89A7E5\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AT2/T71LFYHiI1ppwNiuaewIu2Hq+GWWQ85O8gpWcUxeAQAgBAC2dgYu\n"
- "moxhtuip7GVlthT9iomZKba1IllVa7uE1u2uO9BUYZQWXciFt7OnNzMH5mlffwxB\n"
- "1dWCl+G5nbOsV5jYLbfhrF5afZotf+EQTfob4cCH79AV223LPcySbTHTtQ4=\n"
+ "AQQABstTAWCgrsRHajn+P0SbnvG/WcI46/wS061O1ImRCajjJY8WAQAgBADH8/EZ\n"
+ "onxMi+CrbK3/xNGakEevRzyE2bFAF45l/y8SYeBhcvfzQuGaxuHgIt6D6UAFiVyV\n"
+ "jM+vwjyLTrSicJAPFiVJkbu4tbDijcjr34IlwsAVV/NYX05bX8hVpaSSPQU=\n"
"-----END ED25519 CERT-----\n"
- "published 2014-10-05 20:07:00\n"
+ "published 2020-10-14 20:58:04\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "oypRD2IZQ5EttOE8dvofrW80nnBfijSkvYzBrM6H4KVeayRYvWfmi96dYO6ybMqm\n"
- "Yp7Gs3ngqeeNdfHtkRPuQVUXUGYZgBTvYItuagnFlFgRqaHy0knwUIVOL35eqWYx\n"
- "xSbQKA7fglxEDMFs/RK7FRP4dWc731ZMt5wzzfJHZ8E=\n"
+ "fcD3kYMeOBr4wwKKuRKz7KoHSDIInwYFVnm/kFAMKrSeU+z1MOqchobpp4AuN2p0\n"
+ "BiOLYz621PcTxpURvagwoPcqulkIoWazng9fKyy+ZUk2z9QOjZ2A1PXZVnSKNLxm\n"
+ "P5nNO78Ev5qg6fsYcE40UppOu6mOAXKaKhwyl7ZEvNc=\n"
"-----END SIGNATURE-----\n"
- "\n"
- "\n"
;
-static const char EX_EI_ED_MISSING_SIG_FP[] =
- "2A7521497B91A8437021515308A47491164EDBA1";
+ATTR_UNUSED static const char EX_EI_ED_MISSING_SIG_FP[] = "961B50E8433A0ECDAFFB51FBC951B869BD89A7E5";
+ATTR_UNUSED
static const char EX_EI_ED_MISSING_SIG_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAOOB8ccxbtk2dB5FuKFhGndDcO6STNjB6KiG0b9X2QwKrOZMfmXSigto\n"
- "mtC1JfPTxECayRjLSiP/9UD8iTVvlcnc8mMWBGM12Pa/KoCZRn7McHI3JJ7n9lfn\n"
- "qw9+iZ9b/rBimzOb3W6k3uxzg9r8secdq4jJwTnwSjTObgxZtC8/AgMBAAE=\n"
+ "MIGJAoGBALlAaT9rapqG8s8WuOI/wt9hdIMEZrjFyywelTuY3wDMvWMqKJUX0VCT\n"
+ "TtRco0+Q0QiQcMmcbvWz+BknC7L457XAeBmKckLjSGhu8Ett1/nYiT/wKv4eCOtT\n"
+ "KxkSGkrJX4L9mgdrquwCY6Eq4pUXFHHA2OkE/w25wmbud5GiZ7stAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
;
-
static const char EX_EI_ED_MISSING_CERT[] =
- "extra-info lynne E88E43E86015345A323D93D825C33E4AD1028F65\n"
- "published 2014-10-05 20:07:00\n"
- "router-sig-ed25519 H4gKIKm5K9Pfkriy7SlMUD6BdYVp6B5mXKzR/rTyYlpH0tEZ4Fx2hlHNfNNdWXJieXzKZQZo8e7SOVzvrAC3CQ\n"
+ "extra-info HomersRelay 65EE5370C2EFEC112E351206CF00C4DB89670356\n"
+ "published 2020-10-14 20:58:04\n"
+ "router-sig-ed25519 VaqCeYmnufCStWecAdhxAUs2tBY7DlWBVVtkduk1dJkBzRi9aDTi+7lU80wrYbH1Hb3lykXM+TI5GOabbO8uBQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "dIrbQjK5T9t5KM8CpsMF85hh2i060oPIxzYQMgE1q4j99dtb/n7SE8nhj1Sjij4D\n"
- "7JvTjGdLHi3bFSxXaSmla0wxD9PUYFN7VsBQmwSaDrqrzJFb1SGwZuzW1IEZ7BBi\n"
- "H0czsxEteg5hcNRwISj5WVthuWmau9v13MijtZGSK40=\n"
+ "Bum6OqCQ4asVALAzusLhkn9YgjazJo1Ta4Ff/qubOGcY7JqIC0f7oUfd6D+EhsZS\n"
+ "nRuZjp3KS1jM3gLPaWDI1cGNIG2RwS7QoWjFhjsUAQuBtKVmfBNtdiS9syNLxIlw\n"
+ "zxhm2sGMJ9gxhTIK2noGd36ur+XaQrRousdbkjpwiRk=\n"
"-----END SIGNATURE-----\n"
- "\n"
- "\n"
- "\n"
;
-static const char EX_EI_ED_MISSING_CERT_FP[] =
- "E88E43E86015345A323D93D825C33E4AD1028F65";
+ATTR_UNUSED static const char EX_EI_ED_MISSING_CERT_FP[] = "65EE5370C2EFEC112E351206CF00C4DB89670356";
+ATTR_UNUSED
static const char EX_EI_ED_MISSING_CERT_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALjA/geb0TR9rp/UPvLhABQpB0XUDYuZAnLkrv+i7AAV7FemTDveEGnc\n"
- "XdXNSusO1mHOquvr0YYKPhwauInxD56S8QOzLYiWWajGq8XHARQ33b4/9K2TUrAx\n"
- "W9HTHV1U1zrPlCJtrkbjxsYoHpUg5ljzM7FGYGY5xuvyHu18SQvzAgMBAAE=\n"
+ "MIGJAoGBALir3RWzz5UpiEP+kV4qPtsKzt3C2cwZ0c/k/UusCnszyCVRFJSRa/Iw\n"
+ "Er59Y+Qe/r8ehHts7KXlv9r4CIKGUlXv2YKMI6Dernxnl8e68F3sUyy+GY4a0UJd\n"
+ "sQyMwWcVlOkD6kSUPT4ryAGw3wlL8MAA2xllNl+7Lexpb7VficZLAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
;
static const char EX_EI_ED_BAD_CERT1[] =
- "extra-info marcie F78D8A655607D32281D02144817A4F1D26AE520F\n"
+ "extra-info HomersRelay 82D64A389FBADE8BB38C8F7027EE15B34BBA0CB3\n"
"identity-ed25519\n"
"-----BEGIN PLAGICAL SPELL-----\n"
"aaaa\n"
- "-----END PLAGICAL SPELL\n"
- "published 2014-10-05 20:07:00\n"
- "router-sig-ed25519 KQJ+2AH7EkkjrD0RtDtUAIr+Vc7wndwILYnoUxFLSJiTP+5fMi54eFF/f1OgkG8gYyTh8phMij9WOxK/dsOpBg\n"
+ "-----END PLAGICAL SPELL-----\n"
+ "published 2020-10-14 20:58:04\n"
+ "router-sig-ed25519 q0SZRiMpJ4CG7rebOJk6HzR/TNEmsU7wXDjFYxLMdJgvkQZf9ynsyEIvS9buInsY09czmAFQOUnY2poCBkHeCw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "XWD+P25AH6moi79j20Si3hqKGcJDws+FORL1MTu+GeJLV1mp5CR9N83UH4ffulcL\n"
- "CpSSBDL/j74HqapzW7QvBx3FilaNT55GvcobZDFK4TKkCEyEmcuWKpEceBS7JTTV\n"
- "SvwZeOObTjWPafELbsc/gI9Rh5Idwu7mZt3ZVntCGaQ=\n"
+ "OlhdHgl8dxV4+GRqjsE45qk8QlBYL4+hqSdf4biQGgVGpQv+kbUqzioS8jmiMC4e\n"
+ "VzeFBwEbHxD4OI6C/LWjgOk33uZ3Re7yWnlMqnnWKZOLAEX1/BD4SuTSwlTlzci8\n"
+ "48mzwzTnjh3I1j7ChMm5r/QIpgiC1iwrgw7oVK7mvE8=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_EI_ED_BAD_CERT1_FP[] =
- "F78D8A655607D32281D02144817A4F1D26AE520F";
+ATTR_UNUSED static const char EX_EI_ED_BAD_CERT1_FP[] = "82D64A389FBADE8BB38C8F7027EE15B34BBA0CB3";
+ATTR_UNUSED
static const char EX_EI_ED_BAD_CERT1_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMlR46JhxsCmWYtmIB/JjTV2TUYIhJLmHy+X7FfkK3ZVQvvl9/3GSXFL\n"
- "3USfyf3j34XLh8An7pJBi9LAHkIXgnRbglCud7dXoexabmC+c2mSbw5RnuxDGEwz\n"
- "krXUph/r2b+2UY1CgEt28nFigaHrIQbCmF4szFX/2GPYCLi5SrRNAgMBAAE=\n"
+ "MIGJAoGBAMBDm5sHAbst7tvS5k9sCh6/7b3fEMW9cpARKuK5VR5PdcNJDkxWPTPr\n"
+ "J/Jy0xTqnWrUD0njXpsdE7PKIspn6a5dnk775GmpH8Z8KnRcCrx7AX1Rd0evg4+s\n"
+ "nCPASoD8RlfduLuJ2ZtdGZ8fWOYc2pQmLLYzy0BxoLKC0P9+/CwBAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
;
static const char EX_EI_ED_BAD_CERT2[] =
- "extra-info jaeger 7C2B42E783C4E0EB0CC3BDB37385D16737BACFBD\n"
+ "extra-info HomersRelay 590FDF3A7684E2F9FCC29CFC7941D73570AF5457\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
"AQoABf55Acpw27GZBdwGCgawCj2F/DPadt8F/9DnEWywEew1Yi3qAOtLpCB8KXL7\n"
"4w5deFW2RBg8qTondNSUvAmwYLbLjNXMmgA3+nkoJOP3fcmQMHz1jm5xzgs2lCVP\n"
"t5txApaBIA4=\n"
"-----END ED25519 CERT-----\n"
- "published 2014-10-05 20:07:00\n"
- "router-sig-ed25519 DRQ4MLOGosBbW8M+17klNu8uWVkPxErmmEYoSo6OuH2Tzrcs6sUY+8Xi2qLoV1SbOugJ214Htl0I+6ceag+vBA\n"
+ "published 2020-10-14 20:58:04\n"
+ "router-sig-ed25519 3vgrf5SH8v7s6BNlXH/+RckQExrLwkY9mCgxewnXqvefYzyORy3GAiUQ9Iu0TbldP/Vtf+UgqnaZVbTERCoRBA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "DfdA+DbuN9nVJNujuSY5wNCDLk7Hfzkrde/sK0hVmZRvivtpF/Fy/dVQHHGNFY5i\n"
- "L1cESAgq9HLdbHU+hcc08XXxTIaGwvoklcJClcG3ENVBWkTXbJNT+ifr7chEagIi\n"
- "cVrtU6RVmzldSbyir8V/Z4S/Cm67gYAgjM5gfoFUqDs=\n"
+ "IKKNccP7/3owyYgAC0fnnsyx22Yc7yHqQFMVXwcqV9XH43yhN8KUrbzoZH2pkZzA\n"
+ "0Mn47I82FCd+yQyCmURmWFSAVRQGH8rmBzl+lG9TiRdlBdZfp7YaazQGOVpE6BcM\n"
+ "N4Rh1XY1zV1c82mdQW/JgJ9qDCvflILm597sADqdfyI=\n"
"-----END SIGNATURE-----\n"
;
-static const char EX_EI_ED_BAD_CERT2_FP[] =
- "7C2B42E783C4E0EB0CC3BDB37385D16737BACFBD";
+ATTR_UNUSED static const char EX_EI_ED_BAD_CERT2_FP[] = "590FDF3A7684E2F9FCC29CFC7941D73570AF5457";
+ATTR_UNUSED
static const char EX_EI_ED_BAD_CERT2_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALAM1F/0XJEsbxIQqb3+ObX/yGVnq9of8Q9sLsmxffD6hwVpCqnV3lTg\n"
- "iC6+xZ/bSlTGLPi0k8QLCaTmYxgKwmlMPpbQZ4kpZUrsb9flKdChMN7w8hd48pY9\n"
- "lu8QiAEgErsl5rCCJIHHjrxxM/Cnd0TnedRnj/Z2YqpNx/ggsmsRAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- ;
-static const char EX_EI_ED_BAD_SIG1[] =
- "extra-info vary 5AC3A538FEEFC6F9FCC5FA0CE64704396C30D62A\n"
- "identity-ed25519\n"
- "-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AbPp++GrRb6WphSu+PkMaYsqY/beiLBmtiV3YP5i2JkKAQAgBABKXjg1\n"
- "aiz2JfQpNOG308i2EojnUAZEk0C0x9g2BAAXGL63sv3eO/qrlytsG1x2hkcamxFn\n"
- "LmfZBb/prqe1Vy4wABuhqWHAUtM29vXR6lpiCJeddt9Pa8XVy/tgWLX6TAw=\n"
- "-----END ED25519 CERT-----\n"
- "published 2014-10-05 20:07:00\n"
- "router-sig-ed25519 a7K8nwfg+HrdlSGQwr9rnLBq0qozkyZZs6d6aiLEiXGdhV1r9KJncmlQ5SNoY/zMQlyQm8EV5rCyBiVliKQ1Bw\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "xhZX8Qmgft51NJ7eMd4vrESzf/VdxDrBz7hgn8K+5bLtZUksG0s6s7IyGRYWQtp4\n"
- "/7oc9sYe3lcQiUN2K7DkeBDlL8Pcsl8aIlKuujWomCE3j0TIu+8XK6oJeo7eYic+\n"
- "IA7EwVbdZsKsW5/eJVzbX2eO0a5zyJ5RIYotFNYNCSE=\n"
- "-----END SIGNATURE-----\n"
- "\n"
- ;
-static const char EX_EI_ED_BAD_SIG1_FP[] =
- "5AC3A538FEEFC6F9FCC5FA0CE64704396C30D62A";
-static const char EX_EI_ED_BAD_SIG1_KEY[] =
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMvb6SuoIkPfBkJgQuo5aQDepAs1kEETZ9VXotMlhB0JJikrqBrAAz+7\n"
- "rjIJ4JsBaeQuN0Z5ksXk2ebxtef7oMIUs37NfekLQHbNR0VsXkFXPEGmOAqpZjW0\n"
- "P524eHqybWYZTckvZtUvKI3xYGD6kEEkz4qmV6dcExU1OiAYO9jrAgMBAAE=\n"
+ "MIGJAoGBAK5yV8+I/GiI+Vz6ob7Oecf7TpuLoBPEppLzY3RLv9GqwrIyAhWR7oQk\n"
+ "qrImJE3U+QPdf/Sw/+LG6fIuZPQAyHx8E7FtUBrT6X9gmel+H/4bj40OQhs6nynV\n"
+ "XKnq0tsaNnQrb5ofdFrlCcG+a+ij7gqq1gd9JzITGK7tEdGIMKprAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
;
-static const char EX_EI_ED_BAD_SIG2[] =
- "extra-info coward 7F1D4DD477E340C6D6B389FAC26EDC746113082F\n"
- "identity-ed25519\n"
- "-----BEGIN ED25519 CERT-----\n"
- "AQQABf56AZkSDiFZ1QaiLJhcKdFDE5Kei/sPaPEIEoPMGP4BvOVXAQAgBAAlRLzx\n"
- "U029tgIL9BRe47MVgcPJGy48db6ntzhjil7iOnWKT70z2LorUD5CZoLJs72TjB6r\n"
- "8+HYNyFLEM6dvytWZf9NA5gLdhogbFcUk/R3gbNepmCF7XoZjbhPIp8zOwg=\n"
- "-----END ED25519 CERT-----\n"
- "published 2014-10-05 20:07:00\n"
- "router-sig-ed25519 yfV+GySMIP1fw1oVa1C1de4XOWBqT4pUtEmSHq1h+WrLBNCh3/HZWvNC/denf2YVntuQrMLCJEv5ZaFKU+AIDQ\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "g+BWq69i9CP19va2cYMAXCQ6jK3IG0VmNYspjjUFgmFpJKGG6bHeOkuy1GXp47fG\n"
- "LzZ3OPfJLptxU5AOQDUUYf25hu9uSl6gyknCzsszFs5n6ticuNejvcpzw6UfO1LP\n"
- "5u+mGJlgpcMtmSraImDZrRipmZ3oRWvEULltlvzGQcQ=\n"
- "-----END SIGNATURE-----\n"
- "\n"
- ;
-static const char EX_EI_ED_BAD_SIG2_FP[] =
- "7F1D4DD477E340C6D6B389FAC26EDC746113082F";
-static const char EX_EI_ED_BAD_SIG2_KEY[] =
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALzOyfCEUZnvCyhlyMctPkdXg/XRE3Cr6QgyzdKf5kQbUiu2n0FgSHOX\n"
- "iP5gfq8sO9eVeTPZtjE7/+KiR8aQJECy+eoye+lpsfm3tXpLxnpOIgL4DlURxlo/\n"
- "rfCyv30SYBN9j62qgU9m6U2ydI0tH7/9Ep8yIY/QL8me8VAjLbf/AgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- ;
-
static const char EX_EI_ED_MISPLACED_CERT[] =
- "extra-info msselene 3B788BD0CE348BC5CED48313307C78175EB6D0F3\n"
- "published 2014-10-05 20:07:00\n"
+ "extra-info HomersRelay 8CEBCF8A15C8C1F0537C31C4286E56BDFD710235\n"
+ "published 2020-10-14 20:58:04\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AWBcqjzLESDuLNGsqQ/tHn32XueXwj2fDlgEy/kQNVf/AQAgBAAFOegg\n"
- "XY1LR82xE9ohAYJxYpwJJw0YfXsBhGHqfakEoBtSgFJ3cQAUXZQX4lX6G8IxAlQB\n"
- "7Rj7dPQuQRUmqD1yyKb/ScBgCa8esxlhNlATz47kRNR38A3TcoJ4c1Zv6AE=\n"
+ "AQQABstTAe3zhxsBmvrWABOzif60p/X+9bZrLiRVcYhAMELIWvSwAQAgBAAAyj9D\n"
+ "q/oQQN8BgmK0cUk1kNsnpNOvCNZ9BorUZY+EtFHiND/PYtDe0SNmODVcA4eBvdXy\n"
+ "v5/0QI2S8roW7h1X8V0QVRguZ/3WwJpFE/qLHJ7LWu7kDPqzCjXHE5hQgQw=\n"
"-----END ED25519 CERT-----\n"
- "router-sig-ed25519 Q52JKH9/iMsr1jIPlWHHxakSBvyqjT1gzL944vad4OhzCZuNuAYGWyWSGzTb1DVmBqqbAUq73TiZKAz77YLNCQ\n"
+ "router-sig-ed25519 beLJb1fZrhBz4t6pBCnJl1UGX6QWFoKzbwRwxLUTUHUDyGpPIIbIEdxxem/RPcaYiqXti45lW57v0CEgYktcBw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "YplvAIwExGf5/L8AoroVQXtGm+26EffrxKBArMKn0zS1NOOie1p0oF/+qJg+rNWU\n"
- "6cv3Anf188EXGlkUOddavgVH8CQbvve2nHSfIAPxjgEX9QNXbM5CiaMwgpCewXnF\n"
- "UoNBVo5tydeLHVns15MBg/JNIxUQMd6svMoPp2WqmaE=\n"
+ "BfdqDEu4Qk0SxBTelpzTqjlj1B3Yd0rQO0dftyGLtQmp3gVhUQqiFrW5/R1nTJKc\n"
+ "uOn9o/Te93+OOBLn0joJZ7JpHQJHjcHgW4kCoc2cAYUBEwgCHAa+eV5+jAVQHIm9\n"
+ "YHGkwZNaQct0ZiYnzWtnWzDVLB8ZpJltvYecflLTq88=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_EI_ED_MISPLACED_CERT_FP[] =
- "3B788BD0CE348BC5CED48313307C78175EB6D0F3";
+ATTR_UNUSED static const char EX_EI_ED_MISPLACED_CERT_FP[] = "8CEBCF8A15C8C1F0537C31C4286E56BDFD710235";
+ATTR_UNUSED
static const char EX_EI_ED_MISPLACED_CERT_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALTwNqhTprg1oC6bEbDqwIYBoER6prqUXQFbwbFDn+ekXhZj8vltgGwp\n"
- "aDGl9ceZWDKfi+reR6rZXjAJGctmv0VHkfe7maUX4FC/d2T8N8DvS+3IvJzFMpbT\n"
- "O0fFrDTrCSnPikqFfQWnlP8yoF5vO7wo0jRRY432fLRXg9WqVzdrAgMBAAE=\n"
+ "MIGJAoGBAK0gXKx7t/EMu82I7+XV+/D7zuaZdzInBi/ieys1iiKpYqfSsvIS3hBu\n"
+ "TEWeuCUds9O81RMOqgGRktHPGu+6D863BGlzL+Ib+iih5ceclmYAJ6WvZF7w9enc\n"
+ "JGjP+wwJGWQVKTltlt9y/S/KM7KEGnCf5Biy1ZqJb9V3Fjp8R8DtAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
;
static const char EX_EI_ED_MISPLACED_SIG[] =
- "extra-info grazie 384E40A5DEED4AB1D8A74F1FCBDB18B7C24A8284\n"
+ "extra-info HomersRelay 3D9E654300A20118E237361CBBBBCFC71CA34BAD\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AcGuIBoa6TBqD8Gg5atcwp/+r9ThxIBkULmPv9OSGhv+AQAgBACXH13y\n"
- "mUvdpcN6oRN1nX6mnH40LyfYR5um8xogJZk3oINse5cRNrfMgVWiBpDlJZAwlDDa\n"
- "lx99hzuZBong+CiOcnEvLMsBaVJmNTm5mpdetYclZpl0g8QEXznXXeRBMgM=\n"
+ "AQQABstTAfBKg56c9SNv+Hhf8VjMX2h9s7MS1jPh5WIbHfJ+JgLuAQAgBADdptx9\n"
+ "uqI1om7gmESf4MImZeK+wKjgv0gttLYUyFu39dcjvDoAWdzQXjJMtR5Q2WlEqqPC\n"
+ "Fe41S7M6zYz6O5dbLp4vdDtdr6ZM5gWZwfdxqAfxWKwIsu8IOFOpjAkgVAQ=\n"
"-----END ED25519 CERT-----\n"
- "router-sig-ed25519 TxuO86dQ3pUaIY2raQ3hoDBmh4TTPC0OVgY98T5cf6Y+sHyiELCkkKQ3lqqXCjqnbTLr1/4riH980JoWPpR+Dw\n"
- "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 re8w0o9hmBdpenf9ifhETkcWriJG9sWXDpkogyA4lyQ9MDDrlT7C1IJyGI666ZctCS4lT/btn9/t2Omal4Y7AQ\n"
+ "published 2020-10-14 20:58:04\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "kV2CtArl1VF1nUSyHL00mO3nEdNxlQU5N7/hZNTd+45lej5Veb+6vb4ujelsFERJ\n"
- "YoxwIs6SuKAR4orQytCL0e+GgZsrg8zGTveEtMX/+u//OcCwQBYEevR5duBZjVw/\n"
- "yzpEHwdIdB2PPyDBLkf1VKnP7uDj059tXiQRWl7LXgE=\n"
+ "okoxxnCsf3+V7oKGbmIqiQf7uKDfHOFdamYFGXIFRysn8aZx+o0eMb3I7xlSQfyz\n"
+ "eXdw7m7zHMerCsMLPuWsPBzt9ZPzQ3yvOJWNezzSGtZm8CW/3vLbaxOfI88teIZT\n"
+ "GcqZzbrlvCspGvC2doxep6zQS3ApEdZWpF19/agq2kQ=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_EI_ED_MISPLACED_SIG_FP[] =
- "384E40A5DEED4AB1D8A74F1FCBDB18B7C24A8284";
+ATTR_UNUSED static const char EX_EI_ED_MISPLACED_SIG_FP[] = "3D9E654300A20118E237361CBBBBCFC71CA34BAD";
+ATTR_UNUSED
static const char EX_EI_ED_MISPLACED_SIG_KEY[] =
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAK0HgOCG/6433VCrwz/vhk3cKmyOfenCp0GZ4DIUwPWt4DeyP4nTbN6T\n"
- "1HJ1H8+hXC9bMuI4m43IWrzgLycQ9UaskUn372ZjHP9InPqHMJU6GQ7vZUe9Tgza\n"
- "qnBdRPoxnrZzUOzlvatGrePt0hDiOZaMtDAkeEojFp9Wp2ZN7+tZAgMBAAE=\n"
+ "MIGJAoGBAMLLN1IOWTOw9I3FSQHW9YpDJu4Wdj51vZmXUS3bxxiPinMJo7caSMyy\n"
+ "fyRmgWhzkRKxDXAchBDcLqylvfYRFryIg/fh0zFC6IBvdkHezrJ07KSK4t4TU22I\n"
+ "6luR5LdfNvcAxs3bbHhajvpPeD2iQCcENWdRl5efgtJ8gOeGo0znAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
;
-
diff --git a/src/test/example_extrainfo.template b/src/test/example_extrainfo.template
new file mode 100644
index 0000000000..357bd30896
--- /dev/null
+++ b/src/test/example_extrainfo.template
@@ -0,0 +1,182 @@
+:::comment=this file is to be used with the makedescs.py utility
+:::name=minimal
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+{d.ED_CERT}
+published 2020-10-14 20:58:04
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=maximal
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+{d.ED_CERT}
+published 2020-10-14 20:58:04
+opt foobarbaz
+read-history 900 1,2,3
+write-history 900 1,2,3
+dirreq-v2-ips 1
+dirreq-v3-ips 100
+dirreq-v3-reqs blahblah
+dirreq-v2-share blahblah
+dirreq-v3-share blahblah
+dirreq-v2-resp djfkdj
+dirreq-v3-resp djfkdj
+dirreq-v2-direct-dl djfkdj
+dirreq-v3-direct-dl djfkdj
+dirreq-v2-tunneled-dl djfkdj
+dirreq-v3-tunneled-dl djfkdj
+dirreq-stats-end foobar
+entry-ips jfsdfds
+entry-stats-end ksdflkjfdkf
+cell-stats-end FOO
+cell-processed-cells FOO
+cell-queued-cells FOO
+cell-time-in-queue FOO
+cell-circuits-per-decile FOO
+exit-stats-end FOO
+exit-kibibytes-written FOO
+exit-kibibytes-read FOO
+exit-streams-opened FOO
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=bad_sig1
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+{d.ED_CERT}
+published 2020-10-14 20:58:04
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+-----BEGIN SIGNATURE-----
+V3l9u1uUdGiUPOl8j+hXXw4z/ODeCj/24r2+L32MTjyfUhK49Ld2IlK9iZKlgKYi
+zyoatxdAjU8Xc5WPX692HO4/R9CGLsUfYcEEFU2R3EA=
+-----END SIGNATURE-----
+
+:::name=bad_sig2
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+{d.ED_CERT}
+published 2020-10-14 20:58:04
+router-sig-ed25519 X{d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=bad_nickname
+:::type=ei
+extra-info bobhasaverylongnameandidontthinkweshouldlethim {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+{d.ED_CERT}
+published 2020-10-14 20:58:04
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=bad_tokens
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+{d.ED_CERT}
+published 2020-10-14 20:58:04
+published 2020-10-14 20:58:04
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=bad_start
+:::type=ei
+identity-ed25519
+{d.ED_CERT}
+published 2020-10-14 20:58:04
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_published
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+{d.ED_CERT}
+published 2020-99-14 20:58:04
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=ed_missing_sig
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+{d.ED_CERT}
+published 2020-10-14 20:58:04
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=ed_missing_cert
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+published 2020-10-14 20:58:04
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+
+:::name=ed_bad_cert1
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+-----BEGIN PLAGICAL SPELL-----
+aaaa
+-----END PLAGICAL SPELL-----
+published 2020-10-14 20:58:04
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=ed_bad_cert2
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+-----BEGIN ED25519 CERT-----
+AQoABf55Acpw27GZBdwGCgawCj2F/DPadt8F/9DnEWywEew1Yi3qAOtLpCB8KXL7
+4w5deFW2RBg8qTondNSUvAmwYLbLjNXMmgA3+nkoJOP3fcmQMHz1jm5xzgs2lCVP
+t5txApaBIA4=
+-----END ED25519 CERT-----
+published 2020-10-14 20:58:04
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=ed_misplaced_cert
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+published 2020-10-14 20:58:04
+identity-ed25519
+{d.ED_CERT}
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=ed_misplaced_sig
+:::type=ei
+extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
+identity-ed25519
+{d.ED_CERT}
+router-sig-ed25519 {d.ED_SIGNATURE}
+published 2020-10-14 20:58:04
+router-signature
+{d.RSA_SIGNATURE}
diff --git a/src/test/failing_routerdescs.inc b/src/test/failing_routerdescs.inc
index e2b72c58a0..a612bf8b96 100644
--- a/src/test/failing_routerdescs.inc
+++ b/src/test/failing_routerdescs.inc
@@ -1,56 +1,100 @@
-/* This one actually succeeds */
+/* These entries are automatically generated by makedesc.py to make sure
+ * that their keys and signatures are right except when otherwise
+ * specified. */
+
static const char EX_RI_MINIMAL[] =
"router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAbeja00FtmqpWPIF6GPZtoI0uBiRk7InZ3EV/8U/e1KRAQAgBADZeEW7\n"
+ "LYPn7S5mD4DnQpTVdns8xJtRboTtfqTs6nTpOwWV8+WI94ZME6k6T2FEChi/3qs8\n"
+ "VeCQIM2wW6rEQyUcQzFwqk9bks20K/8x/2vxGopxeAPpJ3glHYqweNM1ZAQ=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAObzT4opT9uaThByupbb96tYxVpGxzL9CRPKUcU0beGpHyognD9USHWc\n"
- "SpSpKfBL5P3xr2i/XTs34M4UTbT9PE7bVyxv7RD/BZmI4gc8R3PMU77xxbpEU5bK\n"
- "LF3QUPpuB88m/2fXUGgMNVDc5MIq6pod2NRoDpeU7WA8T3ewXzK5AgMBAAE=\n"
+ "MIGJAoGBAL2WKwBXssq8ImAdp9VauVXKiKNPsW2ocRlEVsmTLc+R7KORI7ssMM33\n"
+ "1TV5fjKw9a7kSAVKWuthHlpYf8zVosEaECEon2K9zlKPzpGYTfIecKzMTZdjP4mR\n"
+ "Eo10yberjn0W9dRbqCM2Cq6ofJpz8du3o2hDCx4N880Fyr+G1or3AgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 2XhFuy2D5+0uZg+A50KU1XZ7PMSbUW6E7X6k7Op06Ts=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAM1QKsQiup9DNMCgNeE2FkAhCWzpMZKCn1nNlZbDGfE3Z22ex6bdWWY6\n"
- "ocEZ3JZDsZsnaZrdYxrL3Mquq7MbHdfx90EdlOvDRP1SAIbZ55mLR77fZTu4BKd/\n"
- "h9BC6I26uZE0QavFq3+BhoVVhVn5Mqv05nR9CeUMSSZLxw/RJm4DAgMBAAE=\n"
+ "MIGJAoGBANfuddZ47R/rAqf1vgryApzX6k3Lp4kfY8dgortrpeIY2AMrPPBrDc+r\n"
+ "TVBeKRtnlOUstHtZ6ZV9BNUUg1zd0+RlkITWlSRrKXDI8SskNh5RhyB6cYNyKmld\n"
+ "tpyTl1BCvqDb+5QHzNtuQ6zGfo2U2WqZarGEwb5edfPy5iMRNyNtAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key 2kTFTRb+2MmTBjlS9o1bD/1YGQSqYez46+ROA777jGw=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAdl4Rbstg+ftLmYPgOdClNV2ezzEm1FuhO1+pOzqdOk7AGsEQYwHCV65\n"
+ "YCx4fS6zYcrq/nMtz0EfoVyVBbBsRemZ4eXH+a5tOZf6uQDHwE2na8s1sdLB0LcJ\n"
+ "k4lxJJAT6wE=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "1xp9J+HTe7Xz9otke8bGVo0jeTICkbV372X0x4r2Nlex+U4pNMI+H7r2VEn0xCa4\n"
+ "0Mv6huE9/oYVZL0/XgDNJKiYlzDTQvaabvb5teLc31O5AnFS6LvIo0FFflNvaoLE\n"
+ "6h/siROaO9/n3Y56hGNbkg/omkuRsv0+UddLjLxxs8Y=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 WGGVwF/5vU7kD4U3N26vuh5cie0AQc+xmVeV4ikdhGOgChNqqVG5fRN8pl2x0wPJipC1aJwJf9GOamMChSP4Ag\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "Ft/y3JXowjItgfTHwYcZzuUgXrskluoINW5sr+GQoNYE2F4sT8o0tBBJwqJ6FwKd\n"
- "fkIprv9UXqkv5iY+pXSYSI12mY1K5GMNkXiObk46NjuoNNP9l8oidhO6eNfcE+k3\n"
- "CRIYS4FbBaD0fWUSwgMuo0Bp83/Wzp3B9ytEBh0/624=\n"
- "-----END SIGNATURE-----\n";
-
-/* So does this, and it's bigger. */
+ "UQ4017wr2yQlu0wVBuLJlJLWudEGJ+9Z+ZiyJRCrsVauB1L2o+oCK5fsrQeKIWQM\n"
+ "PSJ2o1tXgHAxJixOoTu1tlWNdZeQGNYRh7N2IbRvtwZ1p7NwgM5cG7CCQ/JDiGGy\n"
+ "exMCOnyJpT2pD6KS2SEhbFe4nGxeUnmiJhSFsxAl9Q0=\n"
+ "-----END SIGNATURE-----\n"
+ ;
static const char EX_RI_MAXIMAL[] =
"router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAcDfLx3m1n7Cd3ZUnm+i/fjYWdxZJ2OxffZTq+C5Qhh8AQAgBAD8rDLK\n"
+ "Vraijk0AAOo1CC2vJ+D+E5NwcwrOyKW9Q9wa17CXmHNUAw3LzqxT6RfoWtvKTNZ7\n"
+ "CtrLhi7vW4ypl9u0KC2DUofm2of/vmGDVeNqbe8EYWdvLnU284Xy6GCt6QQ=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANNI56H+b7SW5LMzvXyY5NJzXszsHZZ4O1CPm4CePhBsAz1r0s1JYJ1F\n"
- "Anrc0mEcLtmj0c5+HnhPBNrfpjO6G94Wp3NZMVykHDhfNVDBRyFZMroG8/GlysYB\n"
- "MQPGQYR0xBgiuclNHoyk/vygQhZekumamu2O86EIPcfg9LhGIgEbAgMBAAE=\n"
+ "MIGJAoGBAL0rYefTyz0UxOqvMHkcMN/Otd5PpHQeEOuEI0CwnIe1BaHP9Z3o2T7c\n"
+ "BoIkjYN4WWUss2ymcpFsikHO1/Qt7Jjeg0teLKeRk6kxoBeoXU3jH/XWIZQ72C0b\n"
+ "NDxIvm0ZO8hHXpXySbL7WdUE2FmPZA92+LI02PVh05FNdvPODnTBAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 /Kwyyla2oo5NAADqNQgtryfg/hOTcHMKzsilvUPcGtc=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALvuNVSmg6R9USFbQcNbRjMCJAV0Rwdv0DlS6Rl02ibJgb01G7v391xE\n"
- "d9Njzgf93n8gOrE195bkUbvS6k/DM3HFGgArq6q9AZ2LTbu3KbAYy1YPsSIh07kB\n"
- "/8kkvRRGx37X9WGZU3j5VUEuzqI//xDE9lbanlnnFXpnb6ymehDJAgMBAAE=\n"
+ "MIGJAoGBANPEmrfTxh6KAokO33hjwdCG5VqwSRf8D85MF7as4WrqIvmq3l+yhX4N\n"
+ "rxBXU/oH2NHdkEJp+wDi3ec0U4RO3x5N3c+pkLJ7T3PzX2bqyhXw+M8KFH9OgV8R\n"
+ "uDjeZde+6/I78zf9c93N+44348otSnOIVJi7J2XcKc1nLEg+kaSVAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key XNNdSQl9M8leFmXQy8fR4LBWUpSMAq/5sVrm1gdBcUo=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAfysMspWtqKOTQAA6jUILa8n4P4Tk3BzCs7Ipb1D3BrXAHKPG/YoVIfa\n"
+ "3eEbf1Z5PTnWgUXAPjGnDsVwSRiO+L3cW55varIF4OzANq0YbBVk6DxuSKQRhitV\n"
+ "Em9uzK+n9gw=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "pUhJD9GilzzJmZg7BKErxfjlqABZmV1/6U6MpquraNZy1q5/8Q/VMvVVyqkavLQd\n"
+ "ue3QrEr9bUCG7TcrNYkCS95D0+Pgigzwmrxd7Ry4eBZTwUbm+G2HYLVCFX6YMX2r\n"
+ "kkmsX8KYlVZxgkUPVsbTmjVjWxK9nRN9A7+8shNYzAQ=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject 127.0.0.1:*\n"
"accept *:80\n"
"reject *:*\n"
"ipv6-policy accept 80,100,101\n"
- "ntor-onion-key s7rSohmz9SXn8WWh1EefTHIsWePthsEntQi0WL+ScVw\n"
"uptime 1000\n"
"hibernating 0\n"
"unrecognized-keywords are just dandy in this format\n"
"platform Tor 0.2.4.23 on a Banana PC Jr 6000 Series\n"
"contact O.W.Jones\n"
- "fingerprint CC43 DC8E 8C9E 3E6D 59CD 0399 2491 0C8C E1E4 50D2\n"
+ "fingerprint E9D3 2FC2 7674 5958 C315 803D BAF0 9EE5 C29C 3A0B\n"
"read-history 900 1,2,3,4\n"
"write-history 900 1,2,3,4\n"
"extra-info-digest AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
@@ -61,1509 +105,1431 @@ static const char EX_RI_MAXIMAL[] =
"or-address [::1:2:3:4]:9999\n"
"or-address 127.0.0.99:10000\n"
"opt fred is a fine router\n"
+ "router-sig-ed25519 uBj+IWQchmSBwFO9m2wyaGL2jQ6mz7vx9bUxavKAWovIBtB8b3XCyxOfs7bYP5yXM5MYGcAb2FG0S7BS344pCw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "x5cxL2h2UsEKk2OVnCTxOF8a89HAe/HwQnSlrBy8+l0YdVCcePDJhm1WyWU7ToHZ\n"
- "K8auwreuw+u/n14sQHPYrM9NQE689hP4LC9AYOnrCnMHysfVqKuou+DSKYYRgs0D\n"
- "ySCmJ9p+xekfmms+JBmS5o5DVo48VGlG0VksegoB264=\n"
+ "Y/kIU3v/wA0Uq2mwGyELOMiBqhU2ydgqJVtgH/0oXWvl3YTX3JJCP0lSCWTYFX8N\n"
+ "QZ6zlk9SCPcQ7etUFOZz7XNkDXChZCjRwK921+ko18b+6AK+OCZ1rTi8EepsgTGS\n"
+ "DicGNpmReRVQc9wGWyXsRYS0KBeRBB42gweZ6vlG+6w=\n"
"-----END SIGNATURE-----\n"
;
-
-/* I've messed with 12 bits of the signature on this one */
static const char EX_RI_BAD_SIG1[] =
"router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAYXI0XoJPqR80XqwEbqmiOLL5CwG71dv+66mseJUGu+gAQAgBADAWmwm\n"
+ "dp+JZnolhz8FLdL6abtj+MRbcbhTTg5gDRdcSsc39Bf3UPkhUEhOtTn7tbyNXEtO\n"
+ "iPDCvdR8t4xBgOqDLnNygoqMdCsf2eNYR8hzxXF4zn/La20L4g3hRwX5OgA=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAObzT4opT9uaThByupbb96tYxVpGxzL9CRPKUcU0beGpHyognD9USHWc\n"
- "SpSpKfBL5P3xr2i/XTs34M4UTbT9PE7bVyxv7RD/BZmI4gc8R3PMU77xxbpEU5bK\n"
- "LF3QUPpuB88m/2fXUGgMNVDc5MIq6pod2NRoDpeU7WA8T3ewXzK5AgMBAAE=\n"
+ "MIGJAoGBANhXTGXVE78ronMXn5Im4nML51N69oYpEjh3QqLCq7V19vNCnCbQjcRT\n"
+ "1zHEpL2+HIBHGW7r4phYtq6jRrPOkRk+9A43KMbyYUX8I6Zx/DrryYWKOyZi5Gh0\n"
+ "9VmIp8uwL3oD2icNTIkvAZQ2N2EkMeqkHeqLvHhotDgNvWmOW2+lAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 wFpsJnafiWZ6JYc/BS3S+mm7Y/jEW3G4U04OYA0XXEo=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAM1QKsQiup9DNMCgNeE2FkAhCWzpMZKCn1nNlZbDGfE3Z22ex6bdWWY6\n"
- "ocEZ3JZDsZsnaZrdYxrL3Mquq7MbHdfx90EdlOvDRP1SAIbZ55mLR77fZTu4BKd/\n"
- "h9BC6I26uZE0QavFq3+BhoVVhVn5Mqv05nR9CeUMSSZLxw/RJm4DAgMBAAE=\n"
+ "MIGJAoGBAMAXX3EzjnH+PyThsoj9klX/WZRWSOzzCEKWu4+galdvzex4BRLnFjQd\n"
+ "RWRPcu6jd4eT+niaf0xacmDZuUlObhH0KdMx85JV1DfIO+LicGXwf+A8capCMsdT\n"
+ "E+ZRv+myozxvtYF5dXWWfBtb/HGyLBGP7LbiFM1a9Fy/opdCPI+/AgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key LzriIs6B1YnUXISLCa0Ncgol4tt9coK0TlsyH9L8oyg=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAcBabCZ2n4lmeiWHPwUt0vppu2P4xFtxuFNODmANF1xKABvGX+C/nEsG\n"
+ "zqV/hrnqlfA/+3Pslp9+uPNs7nuq/gfsVlIjcOMcH1wpun1LxJ4CfaHbRoV9Azjm\n"
+ "AbJ4+sLFxgk=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "CLhxMDL3CG8PG1UADvY604uoSwWZ5qDmlHLBc2FkJvdpP/wzovI615W+ew/DA/Jp\n"
+ "i5eHenjefH7LSfzGV1ZbjMZpRASqyHBsyl5nhOUEijRYlRi/LCsJutnOve6rJGfh\n"
+ "dedKLdeCqplto7xhROxvZcqhpwJTC+iJ4ghM4Xcg8Sk=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 stCTjuw9egedA5hdDe1PQoljcLW3Fsg2ZYR3mre1moOd3mxTDI1Hz4uN+ZEDjedG4BNjDNcFY3qDS71Bs5cqDA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "Ft/y3JXowjItgfTHwYcZzuUgXrskluoINW5sr+GQoNYE2F4sT8o0tBBJwqJ6FwKd\n"
- "fkIprv9UXqkv5iY+pXSYXX12mY1K5GMNkXiObk46NjuoNNP9l8oidhO6eNfcE+k3\n"
- "CRIYS4FbBaD0fWUSwgMuo0Bp83/Wzp3B9ytEBh0/624=\n"
- "-----END SIGNATURE-----\n";
-
-/* This is a good signature of the wrong data: I changed 'published' */
-static const char EX_RI_BAD_SIG2[] =
- "router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAObzT4opT9uaThByupbb96tYxVpGxzL9CRPKUcU0beGpHyognD9USHWc\n"
- "SpSpKfBL5P3xr2i/XTs34M4UTbT9PE7bVyxv7RD/BZmI4gc8R3PMU77xxbpEU5bK\n"
- "LF3QUPpuB88m/2fXUGgMNVDc5MIq6pod2NRoDpeU7WA8T3ewXzK5AgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAM1QKsQiup9DNMCgNeE2FkAhCWzpMZKCn1nNlZbDGfE3Z22ex6bdWWY6\n"
- "ocEZ3JZDsZsnaZrdYxrL3Mquq7MbHdfx90EdlOvDRP1SAIbZ55mLR77fZTu4BKd/\n"
- "h9BC6I26uZE0QavFq3+BhoVVhVn5Mqv05nR9CeUMSSZLxw/RJm4DAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:01\n"
- "bandwidth 1000 1000 1000\n"
- "reject *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "Ft/y3JXowjItgfTHwYcZzuUgXrskluoINW5sr+GQoNYE2F4sT8o0tBBJwqJ6FwKd\n"
- "fkIprv9UXqkv5iY+pXSYSI12mY1K5GMNkXiObk46NjuoNNP9l8oidhO6eNfcE+k3\n"
- "CRIYS4FbBaD0fWUSwgMuo0Bp83/Wzp3B9ytEBh0/624=\n"
- "-----END SIGNATURE-----\n";
-
-/* This one will fail while tokenizing the first line. */
+ "aV5gqy5fTtsrdntTPRPGdeN376lXK+blHJuqbAL0WQ7XaMB4r+F8/whFu0cObOqD\n"
+ "AqAhxkcMu721iYCkUNQvhc3FDou2i1mBJFDrhZEtux/2aXODIMG+OPdDUCyBqeQR\n"
+ "oYLLfLR4ZZic1tlBFRRNdtXGF2SHeIM052F7PbeJz2A=\n"
+ "-----END SIGNATURE-----\n"
+ ;
static const char EX_RI_BAD_TOKENS[] =
"router bob\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAY1Po0v0V6qx88GtnuvL+A1OgBABUAjtKSNXR3ZZbB7BAQAgBADilhyL\n"
+ "8kQhWtuPIYxVEQNYAqH/zZCGy7Dj84NEHauI7RaK3GtpbxrIKsMV6oIjyabSSwck\n"
+ "lTBMZ21/EQERwvzyJC6XhSbPIWjI2MpZa5zez+RueZuGhOfqPDidE3sJUA8=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANGCgvZc+JRtAzuzk3gBD2rH9SHrXzjJ1wqdU3tLKr7FamKCMI2pLwSA\n"
- "FZUpTuSqB9wJ/iVcYws+/kA3FjLqgPtzJFI0SVLvQcz5oIC1rEWpuP6t88duMlO9\n"
- "flOUzmYu29sBffrXkQr8pesYvakyXArOJVeRR7fSvouneV5aDYWrAgMBAAE=\n"
+ "MIGJAoGBAOMS5ORipGxb7cm0JEUMxbTh6Jj8t2fMSC4sSAEWtScFVSa5Lc9duuPO\n"
+ "QFRBMFSN7JPp7yv4MiQ/7UWQbm8KeSHwTdLJAaU9IaK8We0oQYPrW5qjHZGexYBu\n"
+ "xy27uSSerxMnk9tulG/AGLQUwTaVVzMZKswvvx4Rerk1QBVQKAzhAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 4pYci/JEIVrbjyGMVREDWAKh/82Qhsuw4/ODRB2riO0=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAML+pYZoYc+whKLijupd63xn0gzlEQqe7k07x/lWMqWFT37FfG6YeNr5\n"
- "fpFoo77FDfuFaL+VfPfI8i88g157hcPKBVX6OyRH54+l5By0tN91S0H+abXjXQpv\n"
- "U/Bvmul+5QpUeVJa1nPg71HRIauoDnBNexUQ7Xf/Bwb2xCt+IJ6DAgMBAAE=\n"
+ "MIGJAoGBANEtuNrjt+lqyvpAOhb1KgoZrtHOVsgvxbQxntUFWxNFWDu0pQ1oeD2Z\n"
+ "sKK1LchHdDAZMo5Hx6Kph8zYtrOW5lP1uo8Q2UfZfkUvmMFWFzPE60Sw7OHW0emI\n"
+ "53qvAsaKcGkqjH7/BqkNhoz+Z7kPrp1hj3bzPJL2WRwl5Oc5v0EDAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key /O0T65ZXDCLznQB8kW5e24GfH5Ep1Hp8Wn72d7MLKHc=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAeKWHIvyRCFa248hjFURA1gCof/NkIbLsOPzg0Qdq4jtALHBaxDDFa82\n"
+ "TnVkxKLU/OQ+b8w1OFtaphO6OUPnF9TCuxcL1Q7uEyD8aVpgSHs6+vAsGEA/iYjV\n"
+ "qNRsst8dAwQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "ILLtKDOLTh4o9trasbxFq0mXfZylPyo3CBjYwZlrSONma9vLmjVob6uU4hugoL9V\n"
+ "Ti5+GgkfNszCiyDJfTkZtL57HtnbHEF6xrMcVDF4j3/ChJR4leaE9IiT2i2Qqe/k\n"
+ "pQVThYaTVooBjuuenqqduGdkQD0sWR0Nd9sormczWbg=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 B/2mFc4gjSmcRguwheihVNruRrqjWWULorDNIIbF2eIER8ZG5DMiG9x57dKf68ga1MeL2Jx6BLhvIHpBxdloBA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "tbxtYYzyVqi6w6jz1k8NPjFvZaSNR0WzixVTTvKKGoMPx/6+Z8QAFK1ILzRUVucB\n"
- "nRhmZMFaPr3vREMErLRE47ODAzwoBCE9C+vYFvROhgfzuQ3cYXla+4sMaRXYZzjH\n"
- "PQ82bTwvSbHsR8fTTgePD/Ac082WxXTGpx6HOLBfNsQ=\n"
+ "ymrdXf4aSaFDb5Qy39rn8u97kKqzs5HZ62dCWLHDyfewUSyNilg7Wt11v4cs7l/7\n"
+ "zizuBHz0Y4E8d6rdoO4PP9KBWFnpcIblaPC5f/SLnNyP93Z6H55gzm1fvTU9cTZM\n"
+ "zKSyCKiUSYpHba5jO70pyR0uOHeu6QhnuphxEN7/KOc=\n"
"-----END SIGNATURE-----\n"
;
-
static const char EX_RI_BAD_PUBLISHED[] =
"router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAdYwLWzkkORAf4oCu7/DXxkHqpAuz/6kHURFX99fxos7AQAgBACvXQAY\n"
+ "eQLaT3/Y512bMp/QFMwqhb3LZJrdQaamSfIkpeQgxtDmcMb2pzU4Qvq34qyBON0z\n"
+ "3yqEUA8PkjK8F/tCayXzftZIMn88qna4OWtytpnRI+qhfkZ2qeCcsXKCTAE=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMoipSwZgTG6SpSOm6ENbyALS1Ljqqa1LSGmtHSRfGYgUQGWZXERXKQj\n"
- "P5ql6o7EbGr1wnispGW/KB8Age09jGDvd/oGhQ9TDFluhLZon3obkZSFw7f9iA7Q\n"
- "s29rNxoeXXLZVyS7+sux70b8x2Dt4CeG8GA8nQLljy1euwU+qYYJAgMBAAE=\n"
+ "MIGJAoGBALoFN+2xSVUeUDh9zMC5O3MRa3T3hS1Uiw0KMgai6TXM4vYvIva5Hsmf\n"
+ "jkD5eERRn9NvYF+dVM6mZqUsra93Q0P93WJjSS0V9Hi4KERAZEJYXpdOq6xwF2A0\n"
+ "fy7AfcxrARjk6Scjqq4WRdWJ80F7fmtRC2aJQx9hrsoYJUylkzc9AgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 r10AGHkC2k9/2OddmzKf0BTMKoW9y2Sa3UGmpknyJKU=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAPzfzQ+2WFMUvnB3z0xD+zwczWcFyYYNW8Lj7/aRGSNN2DICp5uzSjKq\n"
- "qkYQ+C8jG21+MR2PE+ZBmq6CL5mvlFKlWKouXUlN7BejwWf2gw0UYag0SYctae1b\n"
- "bu8NuUEvdeGWg5Odgs+abH7U9S0hEtjKrmE5vvJS5L841IcaPLCFAgMBAAE=\n"
+ "MIGJAoGBALKTuo70dMO6xF89bE/ke4IkN2V9t49UtSI+X607oul59J32YEjCdhOh\n"
+ "mGDw9c/IpUg/fC6yyhNxrVJttKHju3bcHqMTMbkjvyQcEqRRR3f8i5YNmLj3bNxc\n"
+ "vyom0RpyUopuVUx3IFhd1R3MkBVLjMVYOu9zpre8PnDeEtjFNpZlAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key v6c+IGW5pPiYjt/7EUjzO5VAEYETPAAr/qGw3H/N6AE=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAa9dABh5AtpPf9jnXZsyn9AUzCqFvctkmt1BpqZJ8iSlAEzibhI3GhEl\n"
+ "AuLAGw9oa+6KcgVuJb77xBj/9uezeCXCkiPDA6HPjhLsBGlZTchRSZ2CNnRkMB5I\n"
+ "phz7u5XhWgE=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "lyaSCIaSAW5R09tUtkwRvJBDYgCGq2zbgO3hkG8L0XoUAjBU+VyGdqUeWwt3mMeH\n"
+ "nzOTa+oiO4uGbCic8nMXSQMeSD8X1uLTDn5w1QgJlGbJP0nfJyHPzFafIMKPYe9u\n"
+ "bUWThv2WwfygfZLpm9Vtg+wOuCf6CEPUekBtV/mzDkw=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 99:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 4VtXGU7x0OmWCijvK6CGTrKEtEqmbfwau2oIWfmX2anU7rWKrHp29HlBljK62cso22ODdfjDA9xOIUF3/Rx2BA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "G92pnwCIXGJ9Q0fI9y4m/fHpWCsD0Hnk81/6T4TmRH3jt77fc0uRdomUOC5id4kz\n"
- "J2M4vqXwRs5OK+eaPbtxf8Yv6FPmB3OBNCIhwNHIIqzKQStHUhPxD3P6j8uJFwot\n"
- "/CNGciDN+owZ2DzwrXpszDfzcyp/nmwhApbi3W601vY=\n"
+ "CLIS6weTFUdRmbZQXuu6084omWxMbVmbbEvVZcgxNJdFA1Kjj5XLLw4xU9710FHH\n"
+ "FHqftfs5e483aw3ge/A44L03JL6aUeeQiRU7+A4daLq2h+pw7sTM5CzB9nQYMaQQ\n"
+ "1PyCDtVGLPXlFcNyVsJV135RplESfC/SMOJCdqqErew=\n"
"-----END SIGNATURE-----\n"
;
-
-/* Bandwidth field isn't an integer. */
static const char EX_RI_BAD_BANDWIDTH[] =
"router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAaUhoYyIeOU1shTEDUP1aHQqyxQrwwVfEQgqR30hmhxgAQAgBAD/v+wN\n"
+ "v7f62EeJZlcfrx3ar1tVPwbYg+tr8nI6vAsfZ5CnHu+tFZwH/z8wYr99xeLNE1WM\n"
+ "PSS5gecVO5O/dmX2prMLZC+3+wTUNPMPhUeZEalQQmqtm1Lf132P7jQIpQY=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAN32LAvXQaq0p554FcL4LVwnxyiZvscfuFnfpXwWTDRJJHd2+JCttWIx\n"
- "v+eW7dNq+rq/tzSzaZwnp8b4V2skLRojSt6UUHD234eZcsPwUNhSr0y1eMuoZbnV\n"
- "UBBPevpuXea85aSFEXXRlIpQfvFc43y3/UFoRzo5iMPqReo2uQ4BAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMBuF1GvOyVcRDNjzlEmGHJkTA7qkaWgTp33NSY/DPEJoahg0Qswuh2w\n"
- "1YCBqem6Txp+/Vl9hoUoUGwb7Vwq0+YDMSyr0z3Ih2NcNjOMZPVtjJuv+3wXrQC8\n"
- "LPpCpfU9m9QvhQ7f9zprEqUHOQTT0v5j2a5bpfd++6LFxrMUNwbfAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:00\n"
- "bandwidth hello world today\n"
- "reject *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "svABTGDNJOgaiPLqDlkRU6ldYJcoEe2qHlr4O30lVM2hS3Gg6o4QARL7QRt7VepT\n"
- "SruR6pE83xOr7/5Ijq5PlamS4WtODMJSH3DXT2hM5dYYrEX5jsJNZTQ+cYwPQI3y\n"
- "ykuvQIutH6ipz5MYc9n0GWAzDjLq1G8wlcEfFXQLD10=\n"
- "-----END SIGNATURE-----\n"
- ;
-
-/* Onion key is actually a signature. */
-static const char EX_RI_BAD_ONIONKEY1[] =
- "router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANByIdFOKA3r2nnWyLjdZE8oGHqJE62T1zjW/nsCzCJQ8/kBMRYeGDu4\n"
- "SeUJJ2rsh2t3PNzkqJM14f4DKmc2q76STsOW0Zcj70Bjhxb9r/OfyELVsi+x3CsE\n"
- "Zo/W4JtdlVFjqevhODJdyFNLKOvqwG7sZo/K++Hx01Iu0zXLeg8nAgMBAAE=\n"
+ "MIGJAoGBAMJ1zsaN0EPSavqoy/FCS/fbm4MYJFcawEbMmB6mh0cQSR5koddyHeFO\n"
+ "eQZAs9kAPgSOU7Ka1eMTJEZxYqOY3vsqUojdwqV4KGsSaWhPck74D0pZBEK6iaXP\n"
+ "5R7dfo4Z/msPV0w7lWRkgn1WXCEq9Z6RXeW+82kZlq4tgQtwh3xvAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 /7/sDb+3+thHiWZXH68d2q9bVT8G2IPra/JyOrwLH2c=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "svABTGDNJOgaiPLqDlkRU6ldYJcoEe2qHlr4O30lVM2hS3Gg6o4QARL7QRt7VepT\n"
- "SruR6pE83xOr7/5Ijq5PlamS4WtODMJSH3DXT2hM5dYYrEX5jsJNZTQ+cYwPQI3y\n"
- "ykuvQIutH6ipz5MYc9n0GWAzDjLq1G8wlcEfFXQLD10=\n"
+ "MIGJAoGBAKmq+DEg6AMhSUN7MFblSU3TcDg6fpmHANdELEKKIfSTu0uzjqpctZ8J\n"
+ "GY0BHAFx/ckd3Sz6MFYo6UYgsKw93349DFG8KNTwxZH6ZvD1MhLQf1YcT2GRxGIZ\n"
+ "lnisR0FRM8sw1d6gWd69wet9McE0+2BwsD2HgZDmHG5IZfNBq02tAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key 5VBTNKFPXQyw/SIdNg7zgW/pXqTh+VKIo8kObZQU5Go=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAf+/7A2/t/rYR4lmVx+vHdqvW1U/BtiD62vycjq8Cx9nAASWPz85p2Es\n"
+ "QOD8JH26Zc5NWVauFqaTtoOrUnddgpfabhbugZ8jugBc47D9SJhkIMp3EfC6GlPw\n"
+ "W3vOM1ovpA0=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "HY3nfEgabs7A4X1xrKk+4aIZGhrXycSXVaS7Xth0WogrNhK342+OfFkl9VdhYDpF\n"
+ "SLAw54Vu4M9t18fQtDPaVANujrsvdItkm9YEnOATgXR4vFqBDWXO6NJjMpnmkpYR\n"
+ "6OdOu2FpKi5K+WYuUUrkabeXdykPP11rmLx8QGfXKng=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
- "bandwidth 1000 1000 1000\n"
+ "bandwidth why hello there\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 W6O58DzFB5fa36RszIIcRUgLD5M/7CeVEXPjgfn/SVn2EXz2TMzTqZvJpEMSDWx++ZDvQ4x9VCZB35Rvu2SZBw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "Cc/Y22KFvxXPXZtjvGIyQdjm4EMhXVXJEBwt8PvK7qlO1AgiVjEBPkUrTQQ/paLQ\n"
- "lmeCN6jEVcZ8lNiVZgzRQ/2mTO3xLBPj26UNSDuouUwZ01tZ4wPENylNYnLKv5hg\n"
- "gYARg/nXEJiTVe9LHl99Hr9EWWruRG2wFQjjTILaWzI=\n"
+ "tDz9zY+0EzMa7m33Bu6D1GApdsSh06uoVGKpbXT2FqQEa/Pl3xdkNURNIlqMqupi\n"
+ "riyUaVud31+fQtkqV+KpAHBYCfKN6eT6KGloocCx8eK/w22+O/vAnF9wviDJLcg5\n"
+ "q5LyGgs6ZGO6x9VfOScemj8BRjBQ5ro4MRyzSekm3ew=\n"
"-----END SIGNATURE-----\n"
;
-
-/* Onion key has exponent 3 */
-static const char EX_RI_BAD_ONIONKEY2[] =
+static const char EX_RI_BAD_ONIONKEY[] =
"router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAW1xClFKHwnXFI+597t7/uU2mng7CGM9sc7FRKee3UlfAQAgBACPfVQl\n"
+ "9cApxwShdfQ9+w4Akbp+zzrxQjJLwq0Qe7qvKgyl7u1hWyJH/aguIbkCQDPhDUsj\n"
+ "Mc5xVdNamPsWuPRIyxKJLQ9+bhJtUeI3SYc0BwMCUzP4a4EkqeGvvbOEvw0=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKP1kWHsH/BZhNSZmn0FyzIrAHtMl1IVPzc7ABbx+kK+IIEMD9k1fy2h\n"
- "AP2JTm2UmJDUwutVxPsxmndI+9QsRDpu33E5Ai4U1Rb6Qu+2BRj43YAyg414caIu\n"
- "J5LLn6bOzt7gtz0+q69WHbnwgI4zUgUbwYpwoB7k0dRY97xip9fHAgMBAAE=\n"
+ "MIGJAoGBALiWTCyh2ZwplM4DQDwQ1DKVmTInxsuILLmv8DATTZXyMhsBnHf7UPTf\n"
+ "qYZz78V/bW5JSluXYPaLvt1ZteZelLAabbaTl9ezmH0unaXQ7K4lE+Ige/rA0Vfj\n"
+ "YKF/MLdSsEeFj8pAomQvaqUoBgByGHz+eLLVcSAGTvl8hiEXTBSjAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 j31UJfXAKccEoXX0PfsOAJG6fs868UIyS8KtEHu6ryo=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
"MIGHAoGBANBKlyoqApWzG7UzmXcxhXM4T370FbN1edPbw4WAczBDXJslXCU9Xk1r\n"
"fKfoi/+WiTGvH7RcZWPm7wnThq2u2EAO/IPPcLE9cshLBkK28EvDg5K/WsYedbY9\n"
- "1Gou+7ZSwMEPv2b13c7eWnSW1YvFa64pVDKu2sKnIjX6Bm0HZGbXAgED\n"
+ "1Gou+7ZSwMEPv2b13c7eWnSW1YvFa64pVDKu2sKnIjX6Bm0HZGbXAgED=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key wIOhItdhRuyT0Feij9xNXTEPuV9mE6fXU8Y6l1Mjjx4=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAY99VCX1wCnHBKF19D37DgCRun7POvFCMkvCrRB7uq8qAEYfc9irhCYM\n"
+ "WseTLWwjMSClI277sp1lzy1Y7PN/tlQqZkG1mRcGELYARY1cWkj4b2G09oKY41TF\n"
+ "1+EG5BTCSA4=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "E/Sq3MBmp6wnl6QQXI9pt+B2cGzepUMuOvb+v9tN0+YHE81VRHzXORq6kEVRvc5e\n"
+ "t/7qpynQ9QcsPMfPHr/6hFJMHvBKJAKl4ulbdy+dIkKSiwhgp1bXqUV9GoUjDAHy\n"
+ "fw1CA6oKififqoMVqZN6infAVIo7yl6OPAhY1yZLIMI=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 Iw6AuWlz9lT69zV9UjBWiPrenfnuTITlv0YxJlJ00k2kzQTKOTcbEBYrqbm1uDWzgcLqtw2BI48V/VpE9JzFAA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "cYcBOlapA+R4xq3nn5CjpnzNXdDArMlHuXv4MairjleF1n755ecH8A/R8YIc2ioV\n"
- "n/C1TACzFVQ12Q9P3iikVOjIXNxYzaz4Lm/L/Lq4sEOPRJC38QEXeIHEaeM51lE6\n"
- "p6kCqXcGu/51p5vAFCSiXI1ciucmx93N+TH1yGKRLV0=\n"
+ "U15TJrcDOWr7qwtZH46wpAfSZlN/oinnf0a1wPEYQvHditLj6WgH9p4/r0BT8dI1\n"
+ "hi1Y6KWZhMx7/Qwq/MyigMeQelHV2caiWEySKqqfxfa7yore5+ismj0quBTCJaWv\n"
+ "3sM4zWkwaVPvTNtz1btsJYkEKWG3NvPNcZHpxZr2dj4=\n"
"-----END SIGNATURE-----\n"
;
-
static const char EX_RI_BAD_PORTS[] =
"router fred 127.0.0.1 900001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAfb3eBF1wYkkPlk5AHyDmRwtEQDfd7pzfAYRcInfzwnvAQAgBABFNYwJ\n"
+ "gZyXCSt9SbuYCDYXpKt4cPuAW9BCmRHABo7BUcRuOWtfVn0zH5qs4V3490Anu8p6\n"
+ "KHYDAiAS2gfcnTc2OCz1iw1rY1egGjH5+uUIjckdftghs4QOghLVmyUSHQM=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANVi/MVWhzT5uo3Jxw4ElS7UGmA24dnckdkCLetMhZOcE9e9mg4WcImL\n"
- "NuBe2L/9YaL4PFVchCGlq73phKG6yFdqJdjDV8Qh9MJdAYWW2ORrjRvCrspPaYPN\n"
- "BGJrkD2Gd4u3sq7f26TIkzmBx0Acd/FD4PQf8+XOt9YYd36ooS4vAgMBAAE=\n"
+ "MIGJAoGBANKi30IsA+x93+fyVJjP8IC3iF8TWe4lJsYbTCvfcJa0+j/GSPLdxClT\n"
+ "AT4QJkNCNgZcJmo1QqiFAUZHeWs7kKhlSyQT7YLrpSlnjRIBwPBn8ddAY/X67tpS\n"
+ "eXAiWzhpEuzHgle3nCQMlYNUQJp0Yyj6UvK9SiD9B/WCs/ICmWzDAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 RTWMCYGclwkrfUm7mAg2F6SreHD7gFvQQpkRwAaOwVE=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALtP4cIpAYp9nqo1ak4SxALcndFw4o51U36R4oa+uJS/lYQPHkMMOj6K\n"
- "+AVnj9sxkDJ1POaU5lsCQ5JPG1t+Tkh7vDlJb6RCUy25vJOuaQCb9GVVY7KQTJqA\n"
- "E0fU73JdKACNjMlbF36aliQhrG4Fq2Uv+y7yp8qsRxQ8jvzEMES/AgMBAAE=\n"
+ "MIGJAoGBALpZKULTdehX4/NbsioiJ6i3m5YiUe0iKpRnx51VkFOd0HaRdfY1AEyo\n"
+ "FSQtRBYgzugvd6RnWknzcl5r3f38irYS1aAidS4fkTBq1Ce58Yx5iiaHIjylrFlH\n"
+ "3f9N9m/mny5l0QgGvqI+dl94/zr80hDDSxrlH7eIvcIa+BuoTfdNAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key qR1PUvc7ky3rgJ6mWwjNo1aAQZsFZDsJHVy8akTgHls=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAUU1jAmBnJcJK31Ju5gINhekq3hw+4Bb0EKZEcAGjsFRABHNkPpYhab0\n"
+ "ehvtfFPDt90wzDnWsebaqe6EZe+bPSrZCGGDMjgs/1VajEK09zH0FV/F3d5B+XYw\n"
+ "YegiFba6mwE=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "QJCikM5x69I4ErNhwwLTGZ8utGy9P5NjAK+T1BgPOkJJJTzLWz/t5AhLUorAmvC3\n"
+ "fa4byUrVFX8wO6bmnMINaBDVPVlVVcWp2fclI7f9l8q/oCp1GKdmYnyky2RxoXoK\n"
+ "qJBi5CnLCRjpaO36Y4OeUld5jr3gzezDmkD7YQLtzAc=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 9tBjrFWWzCXx3ZUUgDHXykKsi+9sOoSYBneo+QZMtgWPJnYH16sT4eAQ0Y0PYd7OlXOZvOB5u3JX/yCujJpnCA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "xzu2T+pMZtdsS5q1cwXM2hMIH2c8mpAV31G2hKIuiQRwtPD1ne4iJsnoVCXhFakd\n"
- "QTq7eTXM174fGWyIT93wvQx/Uqnp29dGZp/VaNOsxHFdYVB4VIVqkBh757h+PSJ+\n"
- "VNV5JUm4XQ1QbmniJGdTQp4PLBM++fOXMR3ZNd6rt4o=\n"
+ "AKtLxm4FGx5TawJi8kKQL5X8SyQTcDoyHXM+MH8SGjsx3tq560HCK+SGSeoWayGa\n"
+ "s69aHl0nUmH5UMnDOdiWPZqzTi+K5kmO3ik3zkSZQ7/XsUMl+o6In3OkxQrqL7ka\n"
+ "Xdqh3Zz3MT5DE6LBvTSRjnET1Bocfx2+bqkYpUEpxyo=\n"
"-----END SIGNATURE-----\n"
;
static const char EX_RI_NEG_BANDWIDTH[] =
- "router fred 100.127.0.0.1 9001 0 9002\n"
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAbfU59VhOWlweNlw/DQgCRjBh7EtF0hewpRHsuiVKUnTAQAgBABEV12f\n"
+ "2PB6QzHgt/bGosT8rLoBpR16XSi8aqCdurCvr4niKEyudgp+d1h3J8UyB7stQ6T7\n"
+ "qaKCyhXg4v96Rctc8nbi/2HMWvPj+wUqc8ArTrVSH8b3XPijrBU1RLTeFgU=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMCG/ZCXNCF02uXRSCP7qWBN75jDMQZ363ubnQWhF9KDDNWWiwj3UiZR\n"
- "zqsM4zKRgjtarWZvp2qxKABFAODd+j9iq5DvUGRbbXv+aR8TT/ifMtwwxHZQBk1F\n"
- "1hbsLdwWzGIiyz5k2MVhXnt6JTlklH2hgT++gt9YTHYKxkssaq5TAgMBAAE=\n"
+ "MIGJAoGBAMTLuiE+qY3Msi3rgMQ6/jLJu3JyunkZ1MqMTgdqwLi7kPTQHUKg15v+\n"
+ "6xUpEJG9lgdn55OKx4EWda0nntm+TvmPg32ijgX9+hfmQ/euy/kgfrFkN23JAa3k\n"
+ "myqNj9p/LcUML3QFHi7V0mQkcNvXPKOQ001JqW78EGxBccuFQcP7AgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 RFddn9jwekMx4Lf2xqLE/Ky6AaUdel0ovGqgnbqwr68=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAM3vk/4kOTB1VXrve29JeHOzNUsPwKruBcjxJf+aatxjf6KO2/RW41bM\n"
- "gRYq9V7VAYeZTsbS727fy03F5rk3QIBhMJxm9FHatQ6rT/iEDD4Q1UZQsNtm+OLf\n"
- "/TkZZhgfB3MiDQ4ld/+GKd7qww8HXTE+m/g1rXNyZPKozn8K7YUHAgMBAAE=\n"
+ "MIGJAoGBANKNi9dzOok4QWBoT//XU/ok0UySUyZH41gNH5AM1kCMC34DNvfcTnHb\n"
+ "KG57vyi9fUBQPpg6dOTav0feit8v6Mm18v0P1dMUzeFiiu3HjEeoEhpfCRyUGbtd\n"
+ "LSaLLyLrFbM0Ejhh/DJXOdtSKBdPCgdRGceq3z1zihVvqOypm5eDAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key cGIQnSfgCDYXatS8Iiu7MN8iLAoFVageRdeDYd6Y4SM=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAURXXZ/Y8HpDMeC39saixPysugGlHXpdKLxqoJ26sK+vAC2ouHrvGEya\n"
+ "blACfJBgviThszToS+i4ohSdWOXVEvXflIQPjttaduf6+B6YwLTcXnmCVDEq8Z0o\n"
+ "Qc1FSGXkLgw=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "CN6jEFhWkQ3j46kbqRgfH5ngz6exkJj000887E7oinmWITJyVA2oX75NeU4uNdt+\n"
+ "Qrv7bjQIvKyJ+ThzW+E6lNoDbd2Nb+9TkK25tOO7QEzWMOeG2ASvI9NOVlzOktIh\n"
+ "w80DXx5kYgYQ3diDC136rkU4BBdnQDX5aryIqvhESEs=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 -1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 GN+uBj6dVw//1wQfItXo//CCQxgse+Ch45REa7XrJaJJHlThviicTmYL6gH4Ft76n6QElNppbys7MJpL/KuNDQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "bUBBZYZWqCbsH4/7fNXtC/HgIZNGOfDF9v4d9YfKaDs5xDYf2o67hRcwx5imhrgC\n"
- "IU7n9AI4AGxkFoN6g3Y/t4pqebxdkF678rRDCtrlwwreAiUktgrwnetp9Tpo16xj\n"
- "V7Uf6LcqQdvu78lRh1dsrY78sf7sb90vusFMPLXGUKM=\n"
+ "h0ksY36ssG9o8ypJM9gedjDsw816vTOKhiJfaiC/jDdj95aflz3C/WfVviwVPrru\n"
+ "2ThlVuJqESbBykEsW7zBQxJzR3m+1xo3aGpyK37pHx2M7Ys1NkxravfvTw2MVe2C\n"
+ "ZSORjIQZirKTNq9OAPF6h/xxiRvI1tlvMBN6bfeyVe8=\n"
"-----END SIGNATURE-----\n"
;
static const char EX_RI_BAD_IP[] =
"router fred 100.127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAXBpI4NGHpiYtqH9QSueuPqjGjV+NwTGv1Wr7AAEr/lAAQAgBABzxwnC\n"
+ "88ko/02rKCpajAup4icjbr7R2Yzj4i3/d36G8LmUMVTI8TRIwjV9CMQehqfNWMq7\n"
+ "Cmm5b79vpKgjk7ahT/UajbwPxdmec5C72pUiszuTkAdh7OLFeA89BUPkYQQ=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMtMrM24AJpJCevxnseIpRlSuAIMksfkfky2+noe7Rok8xn6AMQzMrwx\n"
- "AiCJ8Jy4DBzIKUiJK4/y1FimyM08qZGR0xeqblCxZ1lbSiXv6OYxoaD2xmWw8zEP\n"
- "Zgu4jKReHh+gan1D+XpAbFNY0KrANhjRo96ZZ3AQsZQcWBiPKCynAgMBAAE=\n"
+ "MIGJAoGBAPG7HhynsWUO4hRHZ9yljs1/DFba8wuw56k//JLHDaM7GXwvfOjzTznZ\n"
+ "Iz8GjT7a0s+XvIqIwBxxUfsffAdRpoUVoJGTvcuLrbYTjVvhZ2rKBgXk1Dy+HOSZ\n"
+ "rF7/3X7n73Jw27g07yB4Ymz7pCrqFTEdHUSEe998IE5yWRwPcJKhAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 c8cJwvPJKP9NqygqWowLqeInI26+0dmM4+It/3d+hvA=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAOPclmBO/amw1RWTSI1y80qY/EPjc0I+sk9HKr0BQOovxqJ0lmy9Gaue\n"
- "y+MOejQ9H2hNev0nd7z1fPxEogt7SCe22qJHHX3xDf+D9RpKsvVzDYZsk7hVL7T1\n"
- "mwHzuiV/dtRa7yAMp7+q0vTUGesU2PYFYMOyPvz5skNLSWrXOm05AgMBAAE=\n"
+ "MIGJAoGBAMWXC95x/pQF+LVa7Z2LKjuL1Zow6+I/2pK5pxqwTv0LiZHEjrCq5Yyn\n"
+ "cXobbDuQqMIQs9MiZl9mceXNz9gORncgN9MGae7mAcQFJIH+Hv5Bp2h1QVpjllcl\n"
+ "yhGFtDVfGjOmr1AUAP2gR7GsmLMzjH6bUtD0o8JujF683x6VRGTDAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key Ue8UgMdiy+jJN+u+N304hAjGzli0ckutdhwTwpJj5Bs=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAXPHCcLzySj/TasoKlqMC6niJyNuvtHZjOPiLf93fobwALDJghOhBUQ6\n"
+ "PvjUF4HdnKk94mFUnVEuXhbDQkqVpUSwqaDgs8pvMps+kysskBrQT9m8UdtvFg+b\n"
+ "7hC2d+i5iwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "fmwhrHV1jQWhrQ3GnQZoY1l2LPcw0kRMEobEyIcDiy3hCTQDQcaChlTVM+fzmcoL\n"
+ "3aF5FFn7UICK8NAJ9P2HyyC185+KEoLKF6haXCMiTWye0tVN/pZgxvwY49WBEkfs\n"
+ "yUcQa9Ixq6BxBjyxaDvsp7zXcdhFKYU3ukI3IAFVlqs=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 +GEY9H7Q+FV5nimwaLadRy4etG7TgGCKal0LqFhHc4L0dXv8EtcplaKUDxivN2u7bm05enwRWr/z/YxvAiR4DQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "g6besL/zxOp0N6Q5/7QZgai2kmCU5EAWJlvZrf5jyrjKhsv2a4LDkap07m9QRFqW\n"
- "GGe7g5iiABIqnl0kzv7NLX7ah+d/xxv+IILXyZfVTxSw0e+zFb3uPlQ7f9JsGJ8i\n"
- "a+w8wyyDBpOAmi8Ny866Cnp9ojVzCyIErUYHFaPvKao=\n"
+ "0fO8rKE3VjyjmF506pxkOH8tIHaN+VBVQViRPE/JmCzBPnaNPIj3FnSaQ3lowlzz\n"
+ "Gy4JE8+/6TS5t2C+MGHUsfTlTZOudtnd09fF/FGERljzzGNx4ABEhGIxf79TG3rj\n"
+ "H0bMCfO3Q1x7X01WZ7f7kreVWC5z6fbrcCgvR7PIxuw=\n"
"-----END SIGNATURE-----\n"
;
-
static const char EX_RI_BAD_DIRPORT[] =
"router fred 127.0.0.1 9001 0 bob\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAeSXj4cWNVaGVBdAZZDkDAdmQFTUpxHYo0ux4eoc7bytAQAgBAC4EaEq\n"
+ "+La3x6f1fJqlT8YhqxetiSdlhLPcFkeWLTOTf3BRXHAQ1EVdiSu76J9il/gn6u4h\n"
+ "j7jaUEIf3v6WovHJ2qAy7wiJRDuXO3aExat3RLJCvqvkaQjgrKFYAmlpDAc=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANKcD6DJ16X3yvdq05jatdwgjO+hyoIpckW9sV/OkdfIZwf+S6Q4pZGC\n"
- "doMw5XeOM52gjpx42kUp6M2WlTGDFEpaNU0VyeZYG/M1CM1xvfj3+1PoebioAGdf\n"
- "GuhNBCHZdaYNiOGnh9t2GgUomgpE6njdS/lovSrDeTL469hfcUghAgMBAAE=\n"
+ "MIGJAoGBALJUtCdVl3BTyy761sZAnKa8N6VOT4QNBLSXxbmVOExMbyr7AVTvOeNk\n"
+ "rrcDbKj35e6fcEFaJbPWHBuHCcRqH54BI2nD4CzR+t0RFSXYK7ZbyM1mhRR4Kshg\n"
+ "WlEAaawZiXte09FAaSNZNrkzdQwXy86JXdZjwjyegfDRj9aaxS3xAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 uBGhKvi2t8en9XyapU/GIasXrYknZYSz3BZHli0zk38=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANWeGHig5wE9UijaNnEW5au3B3hZKSlzCi+T6MYDPbbYhm8qJaVoXUXF\n"
- "EP1EUgzDcX3dPEo9upUA1+91GkjGQCo9eOYlqGib8kHIwKnHZK+hernBc/DnOeUp\n"
- "Wyk9SW5s+fi12OQhr3NGjbSn76FMY9XU3Qt7m3EviTwWpI3Jr5eRAgMBAAE=\n"
+ "MIGJAoGBAL5TunHoAxAC+j3w9P9KmspLn/xl8EZZUfovx9gJ95S/R7uPZYMY1Cdf\n"
+ "d0sObKeV/bdO+7EUT2dpu6ngMj+sS6xam1/VhI0DZemTVHVGh/NOr4P/5Gtgd5+L\n"
+ "g21nRpc77sPtFibJSHhA8M3LGbwZEhbtje4N6r+HlOitX6u69z0JAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key XHq9XhW9b+fh+ZTAUiZw835EI5QzC0t353VeYWUrQFU=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAbgRoSr4trfHp/V8mqVPxiGrF62JJ2WEs9wWR5YtM5N/AD84uDUsUs8x\n"
+ "FOOzaneZZrA38hU/7ocJJ0c8uyAHyJ2FKGsRrLvtK3dbrb1WEyZMTF4U0Ht5tF9h\n"
+ "FYNzHcqFBA4=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "plpu9CjEVOV598popgY9KpeKyXYdhgV4e4cn8xq4ulQOAmqodjw5cd8iEkXYQF6z\n"
+ "g6LT87XHdyLbVOa6Diz8ed7lX6gV0bNLId+mfu+wowTCKp9NxF/+/oZGF6gHrT9z\n"
+ "XsoRUk89LO5JhHMhHH/WdHNe+d6EQGdqMC8oDzrZlTg=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 iIG3Qv7UShaMwFLJRnoplp6iS/Y+oz60D5hLbE41zpH3CzHNz/5dkbDrss5yMWPyWyBC9bZzUytNusyjBWjaDA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "t77wEoLjyfMf9LKgBfjveosgwvJ8Go0nb27Ae3Ng9tGtR4qaJQfmwZ5fOOuVU9QC\n"
- "3s8ww3aY91KD3NTcN3v3FKngxWtRM8AIfwh4pqT3zW6OSP4+nO3xml7ql0Zf6wfj\n"
- "TPFV2941O3yplAsmBJ41sRSWizF04wTtZAIgzY7dMLA=\n"
+ "eK0fcXaG9ZE5PseMnntHv2PQwEiSZZ3T+wrpQb97MwgIrU0zgBPc8fZZemMpiJ6O\n"
+ "f+0SziFXrYWPOOji3fATBHm1w132bE/0lDbUYf17tHMq9/Uvy9cA03f7Vt2+A9tW\n"
+ "xG0iqGpeqoJqg9DcYXbzB58tGkTGwVwSba6MXBRJSnU=\n"
"-----END SIGNATURE-----\n"
;
static const char EX_RI_BAD_NAME2[] =
"router verylongnamethatnevereverendsandgoesontoolong 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAXPRPZ2/Fwcf6Y7r0OZ/DsY50YcgEUsDcYU9SNPRJRolAQAgBAA0NkVW\n"
+ "i3wAeoIg9BeSaD11/nqc5+lOqxsRW5KgrUF5F9EaBcn1mK8QMpZmStY2pyk4PHtE\n"
+ "dAHvytGNgzllNG8ZqCYWQbB38OcYIVp6snV5P6O5FVDzoLHKxB2RZq9CKA8=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAL0mcUxg7GJ6oxgciLiBCbo+NuZ/OVKRrERCSM6j6iHERcB9+ciSRgQ5\n"
- "H6o6FUX2LoRmHYzBk1x7kIjHa9kx9g6CAbBamdZrQbdVnc1y2NrdHB/jvwLj3C48\n"
- "PgzFIrLg9OlkuoWck/E+YpPllONfF65e0+ualgVjPgpQpXwmz+ktAgMBAAE=\n"
+ "MIGJAoGBAK1B43OIRWXV0MifW6xipNWJbezgje3v81ks04dgu4nNi/4opPzV5wJU\n"
+ "3d244I4/KlRgzY4L7D/mxBYtoNtpC2Dae53TkgnLAwHdx77XkoEGuQMjFUtRxejj\n"
+ "KtVUZW5N5kDCG6bItzpmULvRmYoJa0kSGn5nROo4CCiyJSX1tK6xAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 NDZFVot8AHqCIPQXkmg9df56nOfpTqsbEVuSoK1BeRc=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAOgHvvTAxyjJtHx9W2X7aOI05H9sYDDY+sxhovT/8EpAHrioex54tsMT\n"
- "ifgtoXTjGIBEOTDi/1ry39nEW5WPbowqvyzRfR2M43pc96WV7e1nhmD/JrnTYgtR\n"
- "5/15KxcMJxoDhod7WZ/wlXBnHc2VevX8JTaeOe9KYORCj5iNbtVZAgMBAAE=\n"
+ "MIGJAoGBAMWiMIxbssLwJpiCvHvZrg3sbXPMLu/EN3naP1PI0+R2NrlU5AAIEw2X\n"
+ "NeK4LJyBdO4XXBFL+R3HBlUcXjzphHWxeRgYgg85AfF1xhqIgXpzA0AgGRaQ8GcZ\n"
+ "5BZm8fBg8CRiS/DLIgwloQmvOJcUDqYLWqvz91zxeGHK+92msp0jAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key J7+npqmFouE4EuXuQAbhc8d6lGGab27mFTQLeXCnAzU=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQATQ2RVaLfAB6giD0F5JoPXX+epzn6U6rGxFbkqCtQXkXALDsSLNkQF1E\n"
+ "8OpEiD4TyefBcLptg136A7UXqXbC1nWC+xUHYBCgkI5ymEtMHOn9bpl01ULisRH/\n"
+ "29OEIlRPwQQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "tVZrb1HMx1OCvD61ulJgLwwRZz5mLv/qmIXym5JaWApvKPFwUkTeqlMKVD6HwmQq\n"
+ "FWAVIvqZNSA5jkq5PJ+LpM7QBuUrA1tuDVnieCQKpC+iP3Gs9c1aad7jrpciDB9A\n"
+ "MqaJkfketFTtOEa858NWMO/bHAIjcfnGHxRVf3vwIQk=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 +ZJ6ovLWqUfLCwpGqge14MwQfPiWhQYopxbzQQKPtgHnRO5qaMb4K7oIKmMkmKaDchTrz0WyIGFZez6u40qQCA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "j/nFT5gyj20cLHWv94O1jmnqy3n6qkO8Av0OdvvfNeXsMK2UHxk84vzFvEwpUF/Y\n"
- "i+VR3LXY4CjTpuliMtjt7BQGtmJSvB8W0CeIUenIGzfwDxW9dG2o7spDldKDB/OU\n"
- "C1wyHvKaA6Yss/02RIDa4AxyjsfbgdJ91qK+aAnYAtA=\n"
+ "PRiWQYy6k2mmwHHkP0AvQN/r318tQXWGzkNBlwoNwewVTRbq0J6Ds9aIWHAijd4b\n"
+ "vW8E+AHWt3so1ucjq2ix5NwYInhiGHcTSRUqGOKo1WtgcrmGP00g5axZCVxsRDRf\n"
+ "Ev4TNKSLXDRvblNSpYTccuTc/ExvKREplVrajjxN0X8=\n"
"-----END SIGNATURE-----\n"
;
static const char EX_RI_BAD_BANDWIDTH2[] =
"router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAYnSPlxnc+nZZZIokyW+85uwJkjxUDEqTweLYVXCtdekAQAgBAD9bAif\n"
+ "9zqaYAZfgnkiER+TADvD001LseJa0fQEPA8EN+zx+GpjHP2yBU1ZHPo4rtIDoaCl\n"
+ "AioFwzs546cZoZGJsp7U6NDvncqIcu1rGEeOk2MK9Tw7Bfxvi5vkgEO6wAw=\n"
+ "-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALQDCm9VEopiYILmt4X9kP6DQazfgKnLXv+6rHbc4qtmvQQD3TVYbxMP\n"
- "F4sEUaz+YHAPnomfDVW3a0YFRYXwDzUm1n47YYCyhUzEaD2f69Mcl/gLpKdg+QOy\n"
- "boGB1oD4CStWL3y05KhxxTNiTrg+veMzXTqNwryCYm+GoihIAM9fAgMBAAE=\n"
+ "MIGJAoGBAMWlPXGRLRI5kHuR7pMHD977D0XkwSJ5QwrFnbi0FVG5tN79nRRfmZcJ\n"
+ "5DRQAJu35CFo8wgHTJDec9/gXu1gjjDq6SfIcEVjIF1JX/pKC9+CpYbqhGBxTJLg\n"
+ "ysPqgQDq4PdkqSU1FMzcW08FOXmVZCkPTm0J7CwKIefubo/IghjZAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 /WwIn/c6mmAGX4J5IhEfkwA7w9NNS7HiWtH0BDwPBDc=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALYHwdx6bmYy09AW5ElN/DWh0fHh3mBK97ryiIMi8FImYfzbw2BR6xuT\n"
- "aQT5omqS3PNJJcNWZt5gOyDtA9kLh03cch7t1PenXSYJshbME2bDrZDJKVJMN6vV\n"
- "B1v/9HjXsVF50jBzZsJo3j26XCPT5s6u9wqUFWW09QR3E/1HInHVAgMBAAE=\n"
+ "MIGJAoGBAK80UOCQiPEWjOB8yPslBNOEPFcK5AKeA+hIIh6FFceGYxeiIWF5LBIC\n"
+ "5g4dn1GBlUcPX3P/d5m0DXGnGPskwHFyQLpFO0ga4F5HdirTnEUMiko0Nonbrseu\n"
+ "F44Dk+x/KGa1B+8Xr68HZbJGf3kHSlGVDFwVnSBwmRsMjTkW8qyDAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key wrcJB+L6TYel2UOh6d2/11nrQI5TePnxJUZZ54NUShs=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAf1sCJ/3OppgBl+CeSIRH5MAO8PTTUux4lrR9AQ8DwQ3AK0mat83aPjn\n"
+ "XxaHRYZ0M6qHd5NhM0z6RGtw1SmT4AtK1g0ZkcVdDhgzjdu62Y5tU0pzBlK0A9Pr\n"
+ "BW+haJUp4Qc=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "JDqs9wmPisHZOZ0s2Dj6E0jFvFhy6KcXuH0De6Ssud5TJqqY8RNOruJA+OIc5/mV\n"
+ "7rAGsedOETg8d37D09q35RPCPNDC7Ja/Xud0BLeB2VBn3AwxDimHLtp6KyU93CzC\n"
+ "nsUu8iblk6M/hPiinoo8s2qRWj3CvtX9xgkWxrfmI4o=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
- "bandwidth 1000 -1000 1000\n"
+ "bandwidth 1000 hello 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 c5WgGlFiqkcoxrblfnz6S14En3b3F6TkHEqYDg3p9BHA0doDNntOiOJZr6y1hxuZZVxHkGyqz26wqHl1OXWrAA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "p09ijyuvcW+WKRj4mJA/nkLCvZkRcMzykAWheJi1IHCoqhXFdkFLiIRqjaeDVHRr\n"
- "zBtD+YCQiGvFcaQJ9IUhh7IleHcyyljmDYlvuBAxWiKvVZstJac0kclCU4W+g8yK\n"
- "0Qug3PmGKk115x2TllHaCZqMo5OkK4I/WAsKp+DnJ1A=\n"
+ "Vkqau37qjImmyVIa1+w8f8JdXAFiQ1js7gTmkHBxNJrNpNuwAIogOt8KVDwYL3yV\n"
+ "fR3I+kRNjbWn5PfKY8fENtmwj25IpOeJB1UcC3bBpfaUHnUYj4nNLoOxfKO+cOoN\n"
+ "uUhb2jyxJzbSFLuPmIlD5ZiDK9cT/J+Q/o36Ll9TLXE=\n"
"-----END SIGNATURE-----\n"
;
static const char EX_RI_BAD_UPTIME[] =
"router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMM0Nubr1VXQ/FcgIQTFxZpZDlAEh2XN8FoJ8d+X5S46VDGijmMoYmyN\n"
- "oLXqMTGmOaR0RGZOeGLgDzeY8tLrfF821IjfkXeAANZibUjdsHwqHO3wlWD2v+GN\n"
- "0GBocWXEdAp/os229mQQKgYAATJ0Ib3jKhBdtgm5R444u8VX5XnbAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMpyOr4kEtSTZw4H9eSkH2+WmwIlO4VBpY2HkPS00l6L5fM2REjt50Xi\n"
- "lsNOz8Q6mAn5cMYmsGlv61kg01mCvYc7Z715jGh+1hhVAxMaNS3ED/nSPnslyjhq\n"
- "BUm51LhYNHD4ktISIqPMurx6aC8B68UYgKzLgCYNzkathFXSBpjRAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "uptime forever-and-a-day\n"
- "published 2014-10-05 12:00:00\n"
- "bandwidth 1000 1000 1000\n"
- "reject *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "NHYeiQOu0nZdrhSy31Xz4F0T6OTU23hPQDzoLax1/zq6iTVrz9xi3HGm7HhOMW1j\n"
- "YgFGK3+Xm4iJL+DwriunsAIuL5axr3z2hlmFDQHYItP//KyPpOqSrfEOhwcuj/PE\n"
- "VbWsiVYwz9VJLO8SfHoBeHI6PsjQRQFt2REBKZhYdxA=\n"
- "-----END SIGNATURE-----\n"
- ;
-
-static const char EX_RI_BAD_BANDWIDTH3[] =
- "router lucy 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAO6HrITQTEjV/v/rInQ2REmCFZa4dZg8zIh6+B51U/I6hDiZaKGwpNey\n"
- "9OfjoRqT2DwyLEe3ORm9A2RAz2twLBixrpt5IvC0sbGustmW964BHW7k9VvRupwl\n"
- "ovujHpLIj5dkLxD15jGXHoTp1yHUVk9NkMGN+ahg6y+QhTbIrWbRAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAOEpciJFXauEqs31GMTUTzu6edBj9WtV+sIflhGKvU1KKRfwCgOcuKMx\n"
- "QiLHHD9AjhMAFGT/qtNbPFkzfYxHKLHw+NLJsxmNtdkYM26FX3ButPiX+69sq9fI\n"
- "PCHqQy6z/A7hHwtEk6niWgK2PLhAZCg9duAv+mqFVXe2QEBjax/lAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:00\n"
- "bandwidth 1000 1000 electric\n"
- "reject *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "Jk0Xk1RMJSjEflNRcp4qznaHKcfe2r0kOc7TdLAnM8zyNDVj6+Bn8HWmyp/oFmf6\n"
- "xtWKKgkKxriAVIJgqZMchPbr9RuZS+i+cad++FCwpTVkyBP920XWC47jA3ZXSBee\n"
- "HK6FaoK5LfmUm8XEU9BVhiwISXaUfTdkR8HfzugFbWk=\n"
- "-----END SIGNATURE-----\n"
- ;
-static const char EX_RI_BAD_NTOR_KEY[] =
- "router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKYDCSr0Jh9d/mJKjnGYAHKNBcxR3EJk6GGLwKUrRpN8z/aHRxdWlZF2\n"
- "lBml6yQNK/VPftcvOekxrKq3/dISrIFBzFYj6XHNtg31d09UgitVkk0VfRarZiGu\n"
- "O6Yv55GSJ9a3AZDE4YmIp5eBjVuChyVkeDFYKVn0ed4sj9gg35rjAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALXdUQuq1pYHyYP0qU6Ik+oOmwl0eOsuwiLWf9Vd+dsgEszICX4DRWPx\n"
- "syDxfxyA/g9FEPvlI7Nglx6cKe2MT0AutSRLbbML4smfuRZNIF35Cnfu5qTGVVzL\n"
- "GWVSA2Ip7p+9S9xLhLBdc6qmrxEXCPL6anEhCR4f8AeybXAsz2JLAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:00\n"
- "ntor-onion-key s7rSohmz9SXn8WWh1EefTHIsWePthsEntQi0WL+ScVfjdklsdfjkf\n"
- "bandwidth 1000 1000 1000\n"
- "reject *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "Yf9axWyzPudnRvQstNdbtBYo7pGpUEIdECMGcJtFb6v/00pxk4Tt3RiOKa84cOBV\n"
- "7V9NjOLdqlx88pGz0DNCJKqToIrwjZDeQ8Q1yi9XClLDkC32fQRX4y6vNBZ3LXLe\n"
- "ayVrdRrb41/DP+E7FP4RNPA5czujTfs8xLBMbGew8AA=\n"
- "-----END SIGNATURE-----\n"
- ;
-static const char EX_RI_BAD_FINGERPRINT[] =
- "router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAM0wDWF2dBLzsmoIDHRugzosCSR9TSvEE0TkvKu6+agfogGtkQJwQ5zO\n"
- "sGzZbRR+okO7d+QCED2i3rUs1iikoMUT+pwgvOm8Bxg9R64GK7fl9K5WuAiG11Uj\n"
- "DQAfSx5Fo30+rhOhe16c9CT7xJhj//ZKDbXUW7BrJI8zpuOnvgD5AgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKACg1nWM/WjpUiGwlLQsY3Tq1h0RTz/HmOMx/6rTRxS5HLz0KnLg5zV\n"
- "dvmfhxqQVKBkt1N2+y+qO7x71oFzIsFMfHYWSxOCEo8Nkff1BqAPqxxUHvM0HwJo\n"
- "d7lswJ/UT1j4+WZNZ4sFIujsIW2/zZqKlxG9xaw0GXJ082Cj9XkPAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:00\n"
- "fingerprint 5555\n"
- "bandwidth 1000 1000 1000\n"
- "reject *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "mlqyJ/ZGBINKwSNEi7GpNBCMqIVbL0pGAOBYHJF1GbRlU28uRyNyeELIxIK5ZIet\n"
- "ZzKr7KPvlBxlyolScPhTJfP98TFSubrwYz7NnQv0vLI0bD0OyoBf/9/1GYlzgTso\n"
- "3mKfnV7THUalpxe9EjQ/x61Yqf26Co0+jYpt8/Ck6tg=\n"
- "-----END SIGNATURE-----\n"
- ;
-static const char EX_RI_MISMATCHED_FINGERPRINT[] =
- "router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANUAvwbpGbsAyA+mBwjFkvurtRzdw9btDqNKtPImufIE+q+AFTaCnwPr\n"
- "kA7vm/O6h6OhgfdYEC2GfYJfwPGM7MDuz+NnuKxUb3qb2DQN2laqow6qWs9La/if\n"
- "oHKUjC5mNeAgHcbWapx9CygwaFeVW6FBPl6Db6GIRAlywPSX+XMJAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANlSGd+Vm9nLiUk6zgu8dPnSFfw4F0R2GYfmzncIGJWtRFTF9ThW/0av\n"
- "/9vZAWyVBjjtnpAP5R1BzdJYV2RwimC/6tqoHtkSbCBhdq5Cb/EHG7Xgb8KwNWVJ\n"
- "NV1EESDwvWnRfSPGTreRw9+2LkdXri17FhDo2GjRxAq/N7YkLK5hAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:00\n"
- "fingerprint CC43 DC8E 8C9E 3E6D 59CD 0399 2491 0C8C E1E4 50D2\n"
- "bandwidth 1000 1000 1000\n"
- "reject *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "Y8MwYBeEfMhoAABK/FgpVRYolZ7jQ2BJL+8Lb6i4yAuk+HeVmPKTX7MqQoekUuin\n"
- "/HdPKP+g/9HPMS5pCiW4FMwnXAF0ZocPXF0ndmsTuh0/7VWVOUGgvBpPbIW6guvt\n"
- "sLLQ3Cq9a4Kwmd+koatfLB6xSZjhXmOn7nRy7gOdwJ8=\n"
- "-----END SIGNATURE-----\n"
- ;
-static const char EX_RI_BAD_HAS_ACCEPT6[] =
- "router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAJfPJNA3zZ77v2nlX2j5dXImcB/NhRtkG8XQgF7z+3H17sqoXgBgZ1dq\n"
- "IbyJmAy2Lrvk/8VkXNFrT5/ErThn1B98V/PsJOOW1x7jGcix6X4zDYn/MvwC+AxA\n"
- "zNP0ozNcVZ6BzVYq8w4I1V4O3Cd6VJesxRVX6mUeSeNawOb7fBY7AgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKBzfB4mDEJjFTnmtqZxDG8G1yAiccVgAtq9ECEREL/BOQyukixUBeBe\n"
- "j/FgXzbMJ7DZAuopuJZU2ma6h14G63fZs7eNFceDtmdLpuCOsFuvJ5Mlkf3hDZ1u\n"
- "1KK5q+tiG7MKxgnGrqjPBUO2uubs2Cpx0HmsqBNUalXd/KAkFJbXAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:00\n"
- "bandwidth 1000 1000 1000\n"
- "reject *:*\n"
- "accept6 *:80\n"
- "reject6 *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "Dp9dLgs9s5beMPxfD0m96as9gNBvlmKhH1RQ/kcOKscia4R8Q42CnUtIqLkCdjOu\n"
- "zErc2Vj9QzjKOvlqUqHxP+J+l+ZJez6F+E1tcmK/Ydz3exL8cg9f4sAOCSXcpBey\n"
- "llTFDibz6GkQ2j3/Uc4bN/uLzoyZKunpJbSKZP5nt8Q=\n"
- "-----END SIGNATURE-----\n"
- ;
-static const char EX_RI_BAD_NO_EXIT_POLICY[] =
- "router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAK4fbjTKYqv2fygfjzY53sVTdtbNMjq293/uffKKxFYnOVvPzrHlP6Go\n"
- "2S19ZcyDxOuH1unbBChPnV0GpxXX6+bgfDkaFh7+jef0RQ3fpJl84hSvdM8J8SCt\n"
- "Q/F4Oqk3NeKKs+zAHDjhAU1G4LkF9/SZ9WZVXlH4a4pf7xgQtaShAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKahvyDkmh33ob/bLVO1icgz2ntOZN6ZQUfgpMU4Cd6DQtOEwFUGhbVt\n"
- "gvtMHv2+VbxM31ZfUsyBqJ1rJBLpOqlPvSoYwSac2+twa+w/qjfGqcJYhBjP9TV9\n"
- "n9y8DzBX85p6vRcCzcuZ4qUJ2nRzdLHwjdgzeLmmCHuPO2dQxQhXAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:00\n"
- "bandwidth 1000 1000 1000\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "ntgCtMC0VrsY42dKts8igGQ2Nu1BpuzUltisIsJz75dDx2LCqTn7p4VpWbTrj1sH\n"
- "MRNOvEPFxVMs0Lu50ZUGRzeV6GrHmzIRnOIWanb3I/jyrJLM0jTIjCOLwdMRA298\n"
- "tw8Y9Hnwj4K7K6VvgU8LP4l7MAJNfR6UT46AJ6vkgL0=\n"
- "-----END SIGNATURE-----\n"
- ;
-static const char EX_RI_BAD_IPV6_EXIT_POLICY[] =
- "router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKHJKLHqjYoW9M+1q0CGHJRT5u2CnZWb8Qr1DpLkkusQ6ru+cDAG12so\n"
- "IpDQh7IyB2JosVJi9ogekYxJ3O1p5WlFUi0X19DMoer9FJ9J7/3s4enGJ/yMBeuu\n"
- "jLVRkjMJhsfhj3Cykon+8Rrf520wSmBg1dpJQCXTwtb7DARgYRpZAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAPJH61Ir6XSu9/Q9tXGaINbXO1GWQQUXtwh6TX9lxnaCNDLGnxiY+ZZw\n"
- "+Vqj3LAQoMrz1PpPsF5e0VIxok10Vc8y4cWC+kIitcecut4vWC5FYTtVVP9wtlyg\n"
- "YCcVOVhtFQxtLiGqprl84+EVxrR7RQVCMLNDUXIgxAfdnS24eBPDAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:00\n"
- "bandwidth 1000 1000 1000\n"
- "reject *:*\n"
- "ipv6-policy kfdslfdfj sdjfk sdfjsdf\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "XWorzVT5Owg+QcsBtksiUNtpQQ5+IdvbsN+0O9FbFtGZeaeBAbPJ3Poz+KFCUjZY\n"
- "DeDAiu1cVgODx2St+99LpwEuIBx78HaD8RYU8tHx8LoA+mGC43ogQQS9lmfxzvP5\n"
- "eT5WXhkOS5AZ8LZOCOmT+tj/LkSXev2x/NC9+Vc1HPo=\n"
- "-----END SIGNATURE-----\n"
- ;
-static const char EX_RI_BAD_FAMILY[] =
- "router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAM62QoRxSPnm+ZM4fv9p03Qqbz5SzhXYSNjKWqylBruaofTw6oIM8DtX\n"
- "7QnrEe/ou/WtfB+swV/2rt/r0EzmeWBWuDmuSUrN5TC2AdOi9brSJMgXVW6VW77X\n"
- "fuIlLd5DVSId2zs3cKLDqp36CUsooA9sS6I5HrvW9QDf3VS3pGBtAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANg1trpnRzkCi4t4Z4qnBKF612H5A3Zrjg7Jo2b3ajUnON/KEuLPTc3t\n"
- "PPN0W4qqeCMmVQEuxf3DRbTPS20ycy4B/JDWYfxCNwuj5YAx04REf7T0Hlx7Aee/\n"
- "sHEQBhIBfasA2idhTh3cAm4DMYn+00BqjxF6jmyRA0hyntEABabrAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:00\n"
- "bandwidth 1000 1000 1000\n"
- "family aaaa,bbbb\n"
- "reject *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "xOgP3liKF/WEvwbbGzUUVRZ5WPrOI7jex8pZU/02UEnHjit7vCf9fsUcvkeo0xjz\n"
- "n3FQHIO1iAJS7dEaEM4nz6wtPUb2iXSU9QajkGBkJ9/V7NHMFIU3FGfP47PIJJkd\n"
- "nz5INoS+AsE7PmnDjUMm1H45TCCl8N8y4FO6TtN7p8I=\n"
- "-----END SIGNATURE-----\n"
- ;
-static const char EX_RI_BAD_EI_DIGEST[] =
- "router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAJ8Sn8AxBRbeIAHUvaKjqmcYOvXz7YFlpYFiVHp/cn+l+KUkIYTOFQXf\n"
- "K8AtwjmJ4R2qJIbNlY/6oZGFbizt/B+WPuWsTj+8ACEEDlxx0ibg3EJRB8AZYiWv\n"
- "0zC/loiUvHm6fXF5ghvDr9BQzEUo9kBk5haoHwROtGawr1+vOEiNAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMzok3ZJtLjXOC8RKltXI8xulwn/ctCvQFHImR0+ccA1uBxaZNYgiIcc\n"
- "q8XngROfV8xEgDbYPiWiLXJOMSwOd7hfs3YzRWF+LKftYs8PuRyMJcCoBjOPZ4QX\n"
- "HRfTetEvu2SijZMby+lkqpZg2nuF/ipsXUjrabRZdNiIGhC451vdAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "extra-info-digest not-a-digest\n"
- "published 2014-10-05 12:00:00\n"
- "bandwidth 1000 1000 1000\n"
- "reject *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "c/6zAxO04izQvqdM4bZVGE+ak0nna5pz9XZizFkieZEDWGzWQuVMhXyL5sbsFbsx\n"
- "6Hn7DvNRYR/2nA0teDeRyIHMoMHi76te5X9OFDgaeUVCbyJ8h/KZYfPnN86IDbsR\n"
- "dCSmj9kX55keu64ccCAH1CqwcN/UsbplXiJJVG5pTfI=\n"
- "-----END SIGNATURE-----\n"
- ;
-static const char EX_RI_ZERO_ORPORT[] =
- "router fred 127.0.0.1 0 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMc4MOhLG3PKPgc+xYVf4eScWzeOf8wq7Cb/JxZm50G0LuvVbhHtHEZX\n"
- "VOSHI7mLE1ifakJvCFJRLobMU7lU0yhn18/nKl2Cu5NfFHHeF/NieUBSxBGb2wD6\n"
- "aM1azheXrRqvDVVfbI0DLc/XfQC/YNiohOsQ/c9C6wuffA4+Sg85AgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALBWdl9/Vft+NQKQlg5kgvZo+krnhNTRVQojWtUEzom4TFIT+NNKJyMG\n"
- "reQXcNdzNptTB0aOBGGwqAesqzsZ2Hje699NsDe7hdl7Sb5yhKDqtdQY6yDXJUFt\n"
- "zqpAUkmYMLe2p3kPiWefNso56KYXrZrlNAiIS/FhQ5cmuMC2jPydAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "published 2014-10-05 12:00:00\n"
- "bandwidth 1000 1000 1000\n"
- "reject *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "gFg08P9A6QNQjURlebfdhU3DSV0BeM0j2SFza1jF9JcBOWDRmT8FvYFK1B3js6jK\n"
- "8LNV8JOUssv14z5CnUY9CO1BD0xSl+vGlSS4VOXD7rxui8IoWgnqnZsitq+Qzs95\n"
- "wgFKhHI/49NHyWHX5IMQpeicg0T7Qa6qwnUvspH62p8=\n"
- "-----END SIGNATURE-----\n"
- ;
-
-static const char EX_RI_MINIMAL_ED[] =
- "router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf5iAa+2yD5ryD5kXaWbpmzaTyuTjRfjMTFleDuFGkHe26wrAQAgBABFTAHm\n"
- "hdZriC+6BRCCMYu48cYc9tUN1adfEROqSHZN3HHP4k/fYgncoxrS3OYDX1x8Ysm/\n"
- "sqxAXBY4NhCMswWvuDYgtQpro9YaFohiorJkHjyLQXjUeZikCfDrlxyR8AM=\n"
+ "AQQABstQAQvNaHu5qx4lh0J5u39pwIR+4bHrHty+wSqMbmR4i5mGAQAgBAAm5VPl\n"
+ "ChSd6wSrmDX50ZZmvkr3EZwt+R3JtUiYZ77yqVlAGBws0BGvUIbYOUHcS4pWuDSX\n"
+ "KwVT5wktWdgm/VKqZv75Ekbt1HqVAtJVrTXWramFH1JfX+di4xIaYmYRZA4=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAOsjlHgM/lPQgjJyfrq0y+cR+iipcAeS2HAU8CK9SATETOTZYrxoL5vH\n"
- "1BNteT+JxAxpjva+j7r7XZV41xPDx7alVr8G3zQsjqkAt5NnleTfUREUbg0+OSMV\n"
- "10gU+DgcZJTMehfGYJnuJsF4eQHio/ZTdJLaZML7qwq0iWg3sZfBAgMBAAE=\n"
+ "MIGJAoGBAMn6qgw7XEvpr8+99/6trahXGW2laXSQGZzrgLdOAIeCK85uqhOmE15V\n"
+ "4J+fvueDykuU5KpgIjvqC8GdzWWZ8THDMOfi2L4kfnF+KZLAxE2b/M67+8dYlIJY\n"
+ "Xip1Wy9LRmJvlnLpwJtm4R6eYFSANEX1sSkQQKS3mgsJbAx9sOtPAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 JuVT5QoUnesEq5g1+dGWZr5K9xGcLfkdybVImGe+8qk=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAK9NjRY7GtAZnlxrAZlImChXmGzml0uk2KlCugvju+eIsjSA/zW3LuqW\n"
- "wqp7Kh488Ak5nUFSlCaV9GjAexT134pynst8P0m/ofrejwlzl5DHd6sFbR33Fkzl\n"
- "H48zic0QDY+8tKXI732dA4GveEwZDlxxy8sPcvUDaVyTsuZLHR4zAgMBAAE=\n"
+ "MIGJAoGBAKjYRj75Sv9HEGOb+MTtlOkBUHubxF6inexiMOOIeypOTU4tGbxz5CBx\n"
+ "IPMR9HGSxR0maExkaBXjA35zIy9mjAMoclTc/cXdMiD/hJfcPACGBFyeKlblYNKd\n"
+ "clR72dRskggOXPo8wSQMX+4ngB6wOfi6HWH+tT4ZW+VoO8DmraHBAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key 71DgscFrk4i58O5GuTerI9g3JL0kz+6QaCstAllz9xw=\n"
- "ntor-onion-key-crosscert 1\n"
+ "ntor-onion-key eQjy89b9KtHPSi5/+lxGB2L2l98lbxP4wqOwVRbJPzc=\n"
+ "ntor-onion-key-crosscert 0\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf5iAUVMAeaF1muIL7oFEIIxi7jxxhz21Q3Vp18RE6pIdk3cAH5ijeKqa+LM\n"
- "T5Nb0I42Io4Z7BVjXG7sYVSxrospCOI4dqkl2ln3BKNuEFFT42xJwt+XGz3aMyK2\n"
- "Cpp8w8I8nwU=\n"
+ "AQoABstQASblU+UKFJ3rBKuYNfnRlma+SvcRnC35Hcm1SJhnvvKpAHV+58GHOOCu\n"
+ "AdKmVPv2VitBQgdgYhgITdTEo4gHSWSnJ7NSf59IZQmleYAQDFC2ZJUJy0n5zTQj\n"
+ "R4u9ikE2XQk=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "lAZwD6YVic61NvJ0Iy62cSPuzJl5hJOFYNh9iSG/vn4/lVfnnCik+Gqi2v9pwItC\n"
- "acwmutCSrMprmmFAW1dgzoU7GzUtdbxaGaOJdg8WwtO4JjFSzScTDB8R6sp0SCAI\n"
- "PdbzAzJyiMqYcynyyCTiL77iwhUOBPzs2fXlivMtW2E=\n"
+ "mrgyJtcOK97/nva7eGZLk1slPCGmRUm6CvfC/cVrbAiiJF7OxkPEb0SOO8291wKQ\n"
+ "qCxQVXp1Ox/gcILrgRuOTMDDCEAKlYtofKaw+ya3XNqImLtxLNS4MzzNR4kNvuD5\n"
+ "cd9wxTdUZMcbNnWxrwAtp3knuUbv5s+fPB/C9dPK+u8=\n"
"-----END CROSSCERT-----\n"
+ "uptime forever-and-a-day\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 Oyo/eES+/wsgse1f+YSiJDGatBDaiB4fASf7vJ7GxFeD4OfLbB7OYa4hYNEo5NBssNt/PA55AQVSL8hvzBE3Cg\n"
+ "router-sig-ed25519 YZgLS52VJa/LEUkgPEoWAuv6fpmD7BnTIYlxa/gF6OsQiriCTtZp1rg351eoMDt4lxaHFXdiE+uVj+97/thWDw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "wdk26ZtS1H81IxcUThyirANLoszrnYYhOMP57YRAUDEzUr88X6yNDZ5S0tLl+FoT\n"
- "9XlEVrpN7Z3k4N9WloWb0o/zVVidPMRVwt8YQakSgR8axzMQg6QhQ6zXTiYhiXa4\n"
- "mawlwYFXsaVDSIIqYA2CudIyF3UBRZuTbw0CFZElMWc=\n"
+ "O4zO6U4LPp/eEzhLMA1fCdkHW2GxlkvQx4x+v5v/DDf22r3YqQpazRoScAMXgqPd\n"
+ "m6SWYs13ipqs1/9WDLbwv3dPqOAIgGvOeQobQ06Yxqi4nqg7WW+asbM5K7iNIFYZ\n"
+ "SL51DpGbMKDwgRCaobua9LjxzOtrBROKgwpudn4drkM=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-
-static const char EX_RI_ED_MISSING_CROSSCERT[] =
+static const char EX_RI_BAD_BANDWIDTH3[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf54AfsyyHhGluzfESzL4LP8AhFEm83+GkFoHbe1KnssVngHAQAgBABNzJRw\n"
- "BLXT3QMlic0QZ4eG612wkfSRS4yzONIbATKLHIgyzgGiGl4gaSX0JTeHeGfIlu7P\n"
- "5SKocZVNxm1mp55PG+tgBqHObDRJRSgbOyUbUgfOtcbQGUeVgUlFKWZ9FAY=\n"
+ "AQQABstQAZGXxVfBig1quo5wNr6AAbHSuTo8wQga3b0wyrhm49IrAQAgBAD8KBVe\n"
+ "paDp9WBD9Yk6CbO7dqW2bGBYDYHxhMVrAP/xDV2Z7HOjXFjZa5dgz+kcqdxV9BQK\n"
+ "Fvd6c3ZhRpb2jqTKSyoiwwnYOJ0qpbLbHjNC6kIiwzpMKF5/eBIRnL4vugY=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMqT7K8cEzWIaPNXbNgvoZ5ejavoszI2OjW9XXetPD/S2f+N7TfQXHBW\n"
- "bnjpgj87gmk59w0OXTMCv+XofZ0xOy2YR/jG5l1VJIvqgJhhFJ8oSEGVzy+97Ekn\n"
- "Lb1FEYuVfVxSxnU2jhHW6KPtee/gvuyRI/TvZuwmYWxLRpikVn4pAgMBAAE=\n"
+ "MIGJAoGBAMQHT7ehq+M8EKdXLpxc244S7bFsV99WL9B38RS6uWp+Zw5iMhMqBQDU\n"
+ "gLyTzojkB6/MhCQRlai5xmOdexpT9Il9H+C3d2L8A7tHj/58SMH5fUK9Pk91p1xV\n"
+ "pTSkelUNNTTivrkhWYKkZ83N1X9QHEiyM9UOBrx+yQh/ANVOF90lAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 /CgVXqWg6fVgQ/WJOgmzu3altmxgWA2B8YTFawD/8Q0=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAM4nITNe8UykgsIuo5czSSSl3Okr1K+UVWTzDGLznDg77MkLy7mydmk9\n"
- "vf51OB+ogQhozYKIh9uHvecOzY4EhSIuKhui4hNyQklD9juGoW7RVTSpGdYT1ymp\n"
- "dDYS30JBPwCZ7KjdMtXiU8ch2WgbzYBuI+JfjwOhfcsuNC9QPfbfAgMBAAE=\n"
+ "MIGJAoGBAKpe3Vz5SPLedYcIun0NxBb9WHU+PF52CNtyfFSX7ydLk1fEq7ug2Kc3\n"
+ "iT0kZYnYUqIM9tlp94JwOiFLaOfiYdqi1NF8eCHaljf0Fkl+LI4i7+TAxIvSWF9E\n"
+ "00vfFN5vRmH2vnR/tGyM1kbrVJiaBKZLu2FkN7wS5gqXhQl40s3hAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key lx8o212IYw5Ly2KbH2ua1+fr4YvDq5nKd7LHMdPzTGo=\n"
- "ntor-onion-key-crosscert 1\n"
+ "ntor-onion-key VxoUHpKVDO1CwJrUaszxPFyPFBYJpXscprJARNOUFCw=\n"
+ "ntor-onion-key-crosscert 0\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
- "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
- "mjQFK4AtRwg=\n"
+ "AQoABstQAfwoFV6loOn1YEP1iToJs7t2pbZsYFgNgfGExWsA//ENAHxn+CYVO2ow\n"
+ "HY22+Iab30Z52szYAWonI/ivMFc1JXDwhZEYw6p2S9tg5VhPc0EZyFdF1i/HrVwZ\n"
+ "rLdd9n0apg0=\n"
"-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "qAE8PqbI12yeyLWaGyW8TtGv+LNXddZF7hTalGr/Hrd9JD3SrT0sPdn//qQZZbMe\n"
+ "fFAiGR42w8P5XlLXp2O8hbpn24dr0MLAPsxL6YwRBWFCUknPtgnHDau5ycXctUlS\n"
+ "zjLi32GfA3FQKnMUp5tJs5hjbeNAUld7Hi3Lu2z6MRc=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
- "bandwidth 1000 1000 1000\n"
+ "bandwidth 1000 -1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dg\n"
+ "router-sig-ed25519 AO4AMaoDJC3BCSY9WGz/MuOx9IO1jZwEuTM/PTacIB3Q2+6MR+mnuaWDh7fB+IgyGeBgo1s4ScccosxHDBH3Bw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "cv1yL8HhQzQfjzkSosziu2kMecNUQGle4d103h6tVMoZS1ua1xiDpVKeuWPl9Z0+\n"
- "wpFwRkOmK0HpNeOXCNHJwfJaWBGQXunB3WQ6Oi1BLilwLtWQixGTYG0hZ6xYLTnX\n"
- "PdSQIbsohSgCzo9HLTAgTnkyBgklIO1PHJBJsaNOwfI=\n"
+ "LkLZaaP2n1OwlzJZ93jWCO1qegtUqLCh1TyHhpb/PzREJsfsqWATfl14TK+Bhytu\n"
+ "H2xDuGFCejTWH1+g+rh7Fkd33W3SirppNpr9Q7s5Sj8fA51HAWk7nYArSiWYmwBR\n"
+ "ITqgfNVhi192LE2mkgFJeP7SDBcs3dYXTu/nbpwXtXM=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-
-static const char EX_RI_ED_MISSING_CROSSCERT2[] =
+static const char EX_RI_BAD_NTOR_KEY[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf54AXXgm0CUWQr+rxvgdIslqaFdBiwosT+9PaC8zOxYGIsZAQAgBAA6yeH7\n"
- "3AfGIGuDpVihVUUo0QwguWDPwk2dBJan7B0qgPWF5Y4YL5XDh2nMatskUrtUGCr1\n"
- "abLYlJPozmYd6QBSv6eyBfITS/oNOMyZpjDiIjcLQD08tVQ2Jho+WmN64wc=\n"
+ "AQQABstQAeHEwGvEQ6Q0Q4feihyajToFJ/tJdYb7X0U6LJX83+x4AQAgBABfIsFo\n"
+ "zK+xiF5YqrRX9jIluwrJqUXcnRBc6jzzEnMIXCFIlaXAHlR7FtlVjhoUy+pClNul\n"
+ "WcT+JjHbzUwXwAtqhV/tDhLAHk+Ay1vwH1pVlqDBC6UYE1WnAfzUGdGz9AE=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMdyTK/VPZloLUaLsvj1+NOFs33/E9HmA0VgvZ1nNUrR+PxSR71QF7Tw\n"
- "DKz+/p2rJE+MPfQ/Na3dH0vH4CDZ+FH2m4A8SB9emF8aKxdc/7KCjQNDQCNlEQYn\n"
- "O9WvZJhbNPHUmX0z4OotI+Sk3qBzVHu0BGDsPYC9gwszIumDUILxAgMBAAE=\n"
+ "MIGJAoGBAKScAJYuwEgWW/u1K9zpBmTcM2/iwH1yfdQ3MgAcLEGTukHyMb0FJ8GI\n"
+ "zetrQJn0mBY+W/Hb4xylMMz2GL9pgsmGjKxDLcW9at9rA5FXunCEvRkfCvJhhSzS\n"
+ "KDbtTM0030k6uvSo1MQKt1zrntdUXkCDZYl8+yDewb3MfNgOCNZNAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 XyLBaMyvsYheWKq0V/YyJbsKyalF3J0QXOo88xJzCFw=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAL8o6CJiLfW4vdRFvJ2nFt/H/ei0ov83rilOuwSmNORmL9lvnHY++HrD\n"
- "dmEEvBv74xqWJxGbJ6OQ3VOwRpf2X/cb4gAvsQDqDmNwpJsrPYRQVXp/KY/8z7bJ\n"
- "dM4CjcsuJHHmj3yc3iCzgqt/Xr6vR24X4bee12/bP7R8IETvWoiHAgMBAAE=\n"
+ "MIGJAoGBAMpVLmZCeEHM7aRPjxGrcYYTlm2YmFVYkQCMealSBwoP/zMEPnLXODPx\n"
+ "vNx0syUAKg9WraLRoVoTNgHQvPWJCIHULthD61O+S966zItMUoWjD3lfrwZRkA2S\n"
+ "NDvzxUAuxhqS01zfoXGw9jq058b4yhGxdkeloz/6ctIf78dCbfC3AgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key qpNEGrLMVn28Odonk/nDtZq1ljy0fBshwgoAm4X1yzQ=\n"
+ "ntor-onion-key xjiodE8eCJMDycIoosVW5OnhmvEDSn3zQ9uFSpVnI7RI=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABstQAV8iwWjMr7GIXliqtFf2MiW7CsmpRdydEFzqPPMScwhcANqd8l+sKSqF\n"
+ "jfzw43nwQ24k+ktkImehYV443lPygB45J9hfk1Frtf73sdnb3r/Oq3nFfkqTHiZA\n"
+ "vfpkxWg3qgM=\n"
+ "-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "i4RKGIeaUrO6nzfdtb6j+ijYJh1Vgc9bsHMpW9cVCOjoJKFW9xljgl9xp6LytviN\n"
- "ppKYCt9/JflbZUZjny34ESltPGrdquvHe8TtdQazjiZBWQok/kKnx2i+PioRF/xI\n"
- "P8D0512kbJjXSuuq9tGl94RKPM/ySGjkTJPevN4TaJE=\n"
+ "t3ByKPtpGpveOkZI5ArpxDsdjmRbo+vdmqGmDOdUzGEQ7xLZ4tfsul/yvkKNX9WT\n"
+ "f40zkn1kOpEkiNRhpJT1z33yUeGO4Sps8oezTf9mQJCccsTyZ8Jj49V1VSZ2jrAw\n"
+ "J3GJNoqr1lO68HvCA5avXKb8M+uUlB1zoimkTyq14Tg=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 pMAOpepn5Q9MxcV9+Yiftu50oBzBsItQcBV9qdZCIt3lvSFqFY9+wJjaShvW3N9ICHkunrC0h/w5VEfx4SQdDA\n"
+ "router-sig-ed25519 r73EDnNHPxOwmwTR4mcoeM0/P51/WmFnvW/oLzgaR+Cjx1QObZEKO45xqB+QatM0IQ+7H23R2m6cD0iTi6GzDQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "Du5fJYDzvEeGqKTJwgaQsJJgz39K/J4qEM2TZ3Mh0XuDM1ZWDtjyzP03PaPQqbJ1\n"
- "FsN5IStjOqN3O1IWuLzGaZGpGVuqcyYOxjs7REkGQn2LfqCjpzjaAdcsL0fI4ain\n"
- "o/in8GQ6S/qhsx8enKlN0tffTmWmH9bmmVz0+yYmBSo=\n"
+ "SpSRg72z5U5RUIVQymJNyufSYH3RZPdlGweBzUypnaU4+iBum7IB69M2VPE4bchK\n"
+ "EObhVkqTisg6utm6h9HyDUgpgtAIS25IfeRhb713RNdJYeD1KW5KBcmdI5g/eoCB\n"
+ "4N8XrU4+xI6B6chj8I2GiYCMCT7gWFOqAIoJlOJN/UY=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_RI_ED_MISSING_CROSSCERT_SIGN[] =
+static const char EX_RI_BAD_FINGERPRINT[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf54AfoVFYuJnDNBWbjbTqfXACUtXWPipmqEYC++Ok/+4VoFAQAgBADH7JzI\n"
- "fjSMV158AMiftgNY+KyHYIECuL9SnV3CSO+8+I7+r9n+A3DQQmGLULo/uZnkbteJ\n"
- "+uy6uRG4kW0fnuBlKhseJQm9hjNGWzC8hmebp1M+bxwG41EGI7BZvnTrRgM=\n"
+ "AQQABstQARuzNoxmRJWC5XJHiZrz6JnjmLqWZdGCf7gxcyDanXhqAQAgBAC96/co\n"
+ "YtwP7WOha/PdIPmAj9uCv7vl/GtDI7SYowz/i0AqWXGk1T/GIGeSJZ3uSWq9u3tP\n"
+ "ytPSnJvmqj6wMkGLQ7oZsi3G1DTuh/gU4fY3aIAQcm6LEestgnI6RkQF1gY=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALEqlijoFIDX1y1i5zfei8DuDIsFtSw56PGgnMRGcybwD1PRQCheCUZM\n"
- "erQgFCWjgLgvGJERBK/oILW1dFXp4MAR5RgnrPGTfWTinCj32obMLN1gIczpq6a9\n"
- "P9uv6Cz0ApSxpA/AuvjyAZwQKbUXuMvIY4aTprAKSqqVohk6E+E1AgMBAAE=\n"
+ "MIGJAoGBAOhMzS1rZAYB2AZpV9VvAF3twjoMaKuwscP0Z2eFih5/WhUWBSlq0ik7\n"
+ "4XgTYXS1EtV2GjgCE3aIdElr1eBar4+cz58jKssZH5FFWDzPmEN4g6qzifIbsvXk\n"
+ "MeAF1u6wCr/TDJ7srCSp4EL/f6V2y0uC951Z24wKGnRZadBQlmo/AgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 vev3KGLcD+1joWvz3SD5gI/bgr+75fxrQyO0mKMM/4s=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMZbbBjGV7xPri4XNmejq4add93p+XsWlsfbM930bcC2JZiwg4g4cq6W\n"
- "idl8VDmCXeaWg5y3kb82Ch/Q9vPG0QYQbXxUA3JxQKKbcEK3QsEvqQh8Nb7krILK\n"
- "YnSGAnLG2Nc3PnKb7Wpb8M3rAysC5O99Gq1mSfm8ntj3zlIM7NSHAgMBAAE=\n"
+ "MIGJAoGBALdUFqqQlTglmEhthhBDk4ZYeG6NA08jemECh1Eusl+cgiQzvD9nMwdC\n"
+ "euE8OTZkDa2CxlhCdUNV0D67X4hp5C77uJzLGL1LHUeQQaNIkJeMP9A1iZpHcpki\n"
+ "Q9iN/XEMiDK5z42IGc40cimSU1SDCgKquDg+mLyUmQzpo/9GzRvVAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key CYcpfIF4T9PJcfROfVJTUYl0zNd4Ia5u0L9eng/EBSo=\n"
- "ntor-onion-key-crosscert\n"
+ "ntor-onion-key e7xFX5txUS4DxZsux+D2Pz7YGIy60IfBCsxqgSbcCTg=\n"
+ "ntor-onion-key-crosscert 1\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf54AcfsnMh+NIxXXnwAyJ+2A1j4rIdggQK4v1KdXcJI77z4AMRc2LxiKbyr\n"
- "fqRVynHuB031C4TN/HAlNPBjVoRvQRgzpiyyoyCqMDxLZdM8KtzdLLeqZJOXtWod\n"
- "UXbYG3L70go=\n"
+ "AQoABstQAb3r9yhi3A/tY6Fr890g+YCP24K/u+X8a0MjtJijDP+LAH5UAsebB7YK\n"
+ "McQQD2Kt1QtPfkIClLENUG410z6SwWNU1A1p7nJQ0AcCUrsM/5gZfwPzaoEfFZWJ\n"
+ "dmRHtqF/4As=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "BRwRAK2lWxWGS49k8gXFHLEQ/h4k8gOQxM0WgCaN4LjAOilLHFjsjXkmKgttVpHl\n"
- "f0V9ebSf+HgkpQnDSD8ittnr/0QaohUbD4lzslW4e/tQYEiM46soSoFft85J6U3G\n"
- "D3D63+GmaOfIaa4nv7CD0Rw/Jz0zTuyEuARsdJIr1IY=\n"
+ "DO+sLD0Q6Ls39UplbwmIP1kqrYPdUTO1ydHtdEl22+nXbzQ+vIEaMprv77fbOkJS\n"
+ "adq3HQ7WDJ+ESxYyvnOn0rxCv/P4zENgbWE4s10uMWQ5Oqirwlk6peNou9MZ8Re1\n"
+ "1VChxzgerdCJcOOvTW7CCR/7A4QKnn8zu38cT51ncO4=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
+ "fingerprint 5555\n"
"reject *:*\n"
- "router-sig-ed25519 7XfV5r7FXbXPEvrxlecWmAJxat/6VT+/4tE5cHrQnvLM4zslysstWH6/AfIfcmUuDlQ0watmfg1MvVnjavcfDA\n"
+ "router-sig-ed25519 lF577k8aob8csasyKZnvyyfbBze3dgO5QhHRrUCDEoE5bFLRLs50RLwWSn9wNiuOc8tFOFvXqT9o/Y0rziEWCg\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "eigLL3S/oMGL2tJULt9bl3S0iY+YIxdKeGFCcKZci59zD786m+n+BpGM3yPpvrXr\n"
- "bGvl4IBqCa1I+TqPP1rM9lIEcUWaBT7Zo5uMcL1o+zZl1ZWPWVVKP5hC5ehDueu8\n"
- "/blzNhTEFAp23ftDK9PnFf+bXxqbgKkEoZsxnd3e9Ns=\n"
+ "S4yw7hIs9NHODCiTFcSh4YpYHbG4XP3rq9YyJgUG+uWen18N904p+4iQwGh+Ye3T\n"
+ "cHl++4ZkXajAuSm4ZT784/SserPJmxxZroeSMVcdBgGdngOq62kVtfqBRyFDUtBU\n"
+ "CvCb6eHRB+BoKHWcSSyr/abEqO+AfjjWRVEsd7B4PT8=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-
-static const char EX_RI_ED_BAD_SIG1[] =
+static const char EX_RI_MISMATCHED_FINGERPRINT[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf54AR8QC+SNBpPOTVY198IQBANNwZjy+SBqQNxfzjEmo204AQAgBABjz4FP\n"
- "zW/G+fu7YirvANvvqJeb7S1YYJnf6IrPaPsPRzDqJcO3/sTzFC5OSb9iJmzQAWnn\n"
- "ADPOl+nOJC58XJnJ7CUJdPtyoVdMvUiUT/Jtg4RuCN1iDaDYaTh2VavImAY=\n"
+ "AQQABstQAblHLIIIJbgQ7K3DMC/bztGu14OqVAr9A/sTA3/eethrAQAgBACvXlt6\n"
+ "ONBSjN/eXPqM26//TBLhJ880ueBSi2sw+UBpUXqJJsJcW/nChhopJvXkM2LAMF2Q\n"
+ "fnXee5XVoAO50gMaDU7vvh9GVnuAiV4coKDzmDyKVYnGN5CdCk0zj9LlegI=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKuLC0kzCBTV6+WPZcAOQPKjqbjvMIyaehIQS1o90dYM+Tosrhtk3bw8\n"
- "QBLMaiWL3kfIWPZuWi2ai40dmqAXMrXH3yBgKRNZ6zZSbUUuJ1IknqmrQ2PKjC/p\n"
- "sIW2awC6Tq+zrZ7vntDb02zY857vP59j8eolTDg1Vvn6l2ieL+WhAgMBAAE=\n"
+ "MIGJAoGBAKNE/KxjoKl5AIVfvGBm2o863+0/NS3DZsEo0nKaO2n4ZDeAjwezHYl2\n"
+ "HVCod3XUGRrYs4pAz0x7QYcWrI+v1RSy9JqouZeZsCI06lB/4tedve7hUN6nh+9r\n"
+ "AmxK/9RF7O2dosFWTss8ZdK7zYiNTOVcu9nrzpZCsx62TJl48l4VAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 r15bejjQUozf3lz6jNuv/0wS4SfPNLngUotrMPlAaVE=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMnBQPOJBQLZ3NAa70n6lGZGvS3DYZFNOZ2QnHVeVvOSFIFsuvHtnUdX\n"
- "svDafznYAuRFRVqJS2xtKKGu0cmy6ulEbBF+4uAEMwQY7dGRPMgVF1Z33U0CSd08\n"
- "ChCJGPTE7tGGuoeSIGN3mfC4z2v9SP3McBdAiLHisPzaUjfRTcwRAgMBAAE=\n"
+ "MIGJAoGBAJbj7YfrDjilYtStM+ujxajNuayX+IUE2ZXBn4ZD37BAVXSdnoDBnV2q\n"
+ "TMyelhaQlPHHlJKhDnU6l9IJhMYS81rHcavShnbq6xRk/MyIYT5m9a8e9zGjpFOu\n"
+ "++tnFR3CO9QM3PL2gKln9Ta+yRbFJ1Dut6Nx5BOsKQsQwU9Hekl9AgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key W8fUvBpKBoePmqb70rdJUcRT0NhELDWH7/BSXJtkXS0=\n"
- "ntor-onion-key-crosscert 1\n"
+ "ntor-onion-key z3SSwtgbp0wv2AUpqmoRh+r0Ebc4DNy8s0nO9v/IDRQ=\n"
+ "ntor-onion-key-crosscert 0\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf54AWPPgU/Nb8b5+7tiKu8A2++ol5vtLVhgmd/ois9o+w9HAAPwWqmL0HXa\n"
- "bYKrKPWQYnpQHQ3Ty0MmCgj3ABF940JURnV161RlN8CRAOJaeQ0Z8wBRLFC1NqLT\n"
- "+GVdtewGeQA=\n"
+ "AQoABstQAa9eW3o40FKM395c+ozbr/9MEuEnzzS54FKLazD5QGlRAImd//fC+Kly\n"
+ "EP8g9NhXLgNwyYMPv4AVK/IHBodacLoBibzr3tjOEryYVjp5GMjdV31FM48yUMEP\n"
+ "684oirlXMwo=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "x0vT5Wv7Guc0/Vu2BqomWwenh8oda9+8K/7ILi5GQL/WC29Tj51i0EE7PVSnSMJ7\n"
- "33I/V+N5neauqWnbg7TxYaLsPfr6SpPTpBL1Xt0OiwT1//PvPYZ1gCcF3ig3KcfI\n"
- "mreQd5C5Vri6ukWkMtz/zNDaDpDanzaNXTdaUXmFHF4=\n"
+ "iPAp07r37ZfIGSVkunV7GbD4wUg9YTzkfZqqK6v/k+PktFD3ymFMm17xSWB+iDBZ\n"
+ "kPHuPL7n00fARbs7hZxmxB+Z8VV8aIU2o4Tnh91NHVxd1WIfrqNIwKUIXt821Qc/\n"
+ "fhotsrR6u1NGcqHiUZLOq7DFCtX4xvTMXDnQA2Y3F1Q=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "fingerprint CC43 DC8E 8C9E 3E6D 59CD 0399 2491 0C8C E1E4 50D2\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dg\n"
+ "router-sig-ed25519 I1vjiJ3q04pz1mO5zxsoy3ng4y3Ix6YxNEUaO7O83kOiU+VvGmaO+fzlXkTMuAz30BFm75Yckpeiqodak+F7Dg\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "Hci/Br1+NNymDZBmQy1QWMlCeLe8Z1vtZ2ZTj42jDhWg1OC/v72ptI072x4x5cmi\n"
- "X3EONy8wQUvTNowkfG6/V/B768C7FYJYBId1GAFZZymXnON9zUYnE3z1J20eu6l6\n"
- "QepmmdvRmteIHMQ7HLSrBuDuXZUDJD0yXm6g8bMT+Ek=\n"
+ "NRlkV2yLpVDu9fppAPrOyw6rcNvcDjATuZbiwL13KR9NOKFZtF9KQ+qSme4Y8Hcg\n"
+ "hjlVuRiShZPmjq3n6iktNRryn1+ziVrjr6WQQBZyd0HuJ86PAUW8LOC7bI18AzT7\n"
+ "fibS1unSsKBzcFjuP5Uz/ZGABG6lhbgvoleRbAFbd4s=\n"
"-----END SIGNATURE-----\n"
- "\n"
- "\n"
- "\n"
;
-static const char EX_RI_ED_BAD_SIG2[] =
+static const char EX_RI_BAD_HAS_ACCEPT6[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf54AW8fyx54c7vQQA/AmShAitFP7XI1CLdifEVPSrFKwYq6AQAgBAChqjVA\n"
- "/wKKJZ30BIQoXe5+QMiPR6meNxF1lBttQ2t5AhauZbH5XzRhZkdGo114wuyPNEM9\n"
- "PrBwp5akTtari9doVy6gs3McqdoIbRdWevpaGj5g5oOEOtA9b5UNWQSwUAs=\n"
+ "AQQABstQATlCWYR3MJXT0ttJyn6HikvWxiw1QlFMUv6P9aVNxSeoAQAgBADrOgV7\n"
+ "plvP37tRpQENPGYV8J0+hJAK5YcnEtfnPFSIf2TimQb9VZZ4Zcn/7WLIsAkWP7lu\n"
+ "BPY5GC8YPPz5kaHDkrsX7LExapYw0KrrLrHHOf3DWuNayjzRfkPFOIitIAI=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALp0Croi9zhpGxi9sUj54jr/flZdzxVVS+8VNldJG2c1soSx8kwlwotu\n"
- "7mGGudJDAzDHGo5F5CCPEfQov2OmDehpefYUz/AaMLly6PrLRJlcUcpLogGf1+KU\n"
- "1lLwE8kanXUkgvDhVQiFvNjy2Dxxuv3AHH4WdZZfbMbm8FJRGoHzAgMBAAE=\n"
+ "MIGJAoGBANEcIzy+Sq/G43SLJDO9cVZWUC9aPR6VX+C3A7nToJgl7eqRuI9EWdLc\n"
+ "ORZTRoLWfEeu9ciJpjfOdIt45Sz23lZ1ZULRQEOrgZ4rXMolSdVYMKPKuldvj6fz\n"
+ "t4QRUdkVGISNn7lVmdF6Dti6NNMdS0H+vFM4C6OK7qc1WY2qD3NlAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 6zoFe6Zbz9+7UaUBDTxmFfCdPoSQCuWHJxLX5zxUiH8=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMoI9vQT4g2sV2dViGOWOzxckk367T9sMjVwcYfJCmnixGxjWeKScQFB\n"
- "K9v1uK73cfZR8AxiUGK4/iOX/9en14mJOGF7fftAqypFLAt1TBvb07IgXljOBoHc\n"
- "Paw4oZoJQzEoazt0Oa181LyNnNIoaZpHVZd1+a1Gs1gKoM4xDBv1AgMBAAE=\n"
+ "MIGJAoGBAOChxY+BMY6iajCYdjz3My8oqJw++gvhnH3aQk+a+pmXO5dFnSeWnnxU\n"
+ "7kue4Kc/F9C5ZLdArObXegUYE7nge3Sss0gxlNj8E1eItCkh5mDXKxj4wGoYFxqi\n"
+ "tMuJIcMSkz6mt9iOIC/33AcFLHCH2fEPL9lNqKZw324+2B/HwBkZAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key KjyvXYkMcpke5ZsUYf2gZAUNeEoz8NAwYoQvvbcDGiw=\n"
- "ntor-onion-key-crosscert 0\n"
+ "ntor-onion-key oOTk28yuw1rfN9ieyNcjsR41nmWZ3sMl7WAq/8rIyWU=\n"
+ "ntor-onion-key-crosscert 1\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf54AaGqNUD/AoolnfQEhChd7n5AyI9HqZ43EXWUG21Da3kCAI6MRHm7GpCF\n"
- "/3zDGR/6jKe625uFZX9HpLt6FgAdGSJeMQ9W4Np9VkrFXAB3gvh7xxRzSgZ1rXgR\n"
- "lUomgi7N1gc=\n"
+ "AQoABstQAes6BXumW8/fu1GlAQ08ZhXwnT6EkArlhycS1+c8VIh/AFfG1jFn0GEz\n"
+ "Izr4UdQrqbSIW4GnGZt/cWF+5GgrFqVLKjLQn0qL59+RcI5uL8t4HYMeX7DDW05D\n"
+ "kFEyCR0K3QM=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "xJXvCCpP4ExBuT3OTsdn2HJB0HidupmQq5zBh8fx/ox6+047ZBOM7+hVxxWapcMg\n"
- "PMXbcLD4L/FCBpA/rjnFUE/9kztdq7FH/rOdi0nB6FZWhwDcsZuyfvbnDTxz5iHJ\n"
- "87gd5nXA5PE649SRCxW5LX0OtSiPFPazu4KyyBgnTIM=\n"
+ "WiHEajyWxVHtfGW2zk1P/oiayJ71SooJ5h8VTJvt3Ll6EwTk0OLKrT+WHfnKyIsx\n"
+ "Zc0ocAD/fB89k8aD9doEbyGhtxYOnbHzm+Bu/HBpHcsom3sJ8V5dAG7T0SsA2e7j\n"
+ "/nUR/px6AhyLRVTPCwHJffU7BgCBpZR5qpxwE6iFJec=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "accept6 *:80\n"
+ "reject6 *:*\n"
+ "router-sig-ed25519 UPASGxdHFoEI9MK012Ip83qfdYAAAaaDpr/2xn4dDozCGisojWJ1Cdv5HDLpXRsdcjkvOjg48XQHMiFQHLWEDg\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "tk4kBNYqB8utOmX30HrV8YfnwBXYODIiL3M/juRS6nPn0uvbW7pjoZ3ck/ahgW+6\n"
- "FNQsgTJnEADCWS1r6v7PcvzQjtrOUUpNxGJxYw1r8yZkvmIxSQD6GMzuTxq7o1VA\n"
- "/wZYDLonLhCWRdPjxnrl12+z92NdyISJCHMLRVqs2QY=\n"
+ "m+JqBjl516GHFnz/BMCX2Fc3vJkZxcstqa1+QScfj+hagYlW97SyUSTlGrNJcP0R\n"
+ "F6ZP5p8DFRoyMPLUsHv3cXodSCmmlGYZLctIAlAwNPyvjx8K4viE4/ImEemoKWzd\n"
+ "D1ylziMbpPYQ//9w3a5zNrOuigFGKyQJdtc4eKbMkQM=\n"
"-----END SIGNATURE-----\n"
- "\n"
- "\n"
;
-static const char EX_RI_ED_BAD_SIG3[] =
+static const char EX_RI_BAD_NO_EXIT_POLICY[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf54AYYiKZrFWZ/Cj5mZbfK11MZHYbwchllsUl4qPqY9gfi6AQAgBAB4irxT\n"
- "86FYA0NbZssSTmfyG6Edcf0ge61OwB4QD35kHCrvuZk2HnmL+63Tj4QoFqIVnwVC\n"
- "3wRGJGcmS7y+vS64GUXbuyTgqgpl/KuoHo5Aqe6IxJlVWYtU6W0M6FV9tAM=\n"
+ "AQQABstQATYAnLUERikTHIW5W60T/eDjs/+G8GViekaCOpm7O5oAAQAgBADvnTrF\n"
+ "bsB6EXhry4mELlXb0xIK+zDsMniuXXOs3dZhondVXKfc/6XyytBWFt3V2323aYwg\n"
+ "W1uRiwqrqdbGGCelO6Vfp02HtSKOUELhzb3XRfJjrTTOf/ov0TFKqZq4oAo=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMUEvXTVTl5xkQ2MTEsB4sXQ3MQkz8sQrU63rlqglpi1yUv24fotjzvE\n"
- "oJpeKJBwwg5WBW/fW0bUDJF2cOHRHkj/R4Is3m+2PR1Kn3UbYfxNkFkTE11l099V\n"
- "H6xlsi0TJOJKlgrcbSuB7se2QctZVhwsdsJvFRptC9Qd+klAPb7tAgMBAAE=\n"
+ "MIGJAoGBAKKGX1tx5+kYDoBULSeIl8Yj+bfOwoQACHT/S/W9Mt3OKcfrjjaUxxoY\n"
+ "TYu9W4m0CbVOmTcNnB/StDwub+fhFgg/jf8dUywFuzl8Dv0+Elvd6rhr8sQO6UWm\n"
+ "nUpZL4yvOVehl5pcY9lIUYX8SE6akUCLo6S1mJ1/aUnNK6i9TxSrAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 7506xW7AehF4a8uJhC5V29MSCvsw7DJ4rl1zrN3WYaI=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMooTeSUX7GPoyklSd1/6cF1u8e2LbjOLIpZrMon0Xt7c/aNwlrG9rVo\n"
- "TSokHs3AQ2H2XIceySVRRWR4AdX9KApO4CX0gGTuVUmq6hFJWMnHdAs2mKL0kt1w\n"
- "I+YWzjUqn4jIVa2nMbyHVQWzIysWwWiO4yduIjAYpBbWd9Biew4BAgMBAAE=\n"
+ "MIGJAoGBANM184uIu8XUgWZBARcAOJSZ9UxN2aecqJ0QcicJ/OSt1GDrxrmIuvCh\n"
+ "+lGA2dT1uqGVJrrSKMQoBYsvJXK1gMFwvhl9pjg4LGkXLS3CUJffjwSxRJ2wF8Ga\n"
+ "yVC8SLWJqFPE7/ReWLES5Qx8/LqpJwIORwQbJc9r2g325U07HYGLAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key BN0I+pLmFkDQD5iRsdkcped4eZwGIuXnLiX2K0Zoi2I=\n"
+ "ntor-onion-key jQrLewVdDUe3MvTdLNB9H2Is2mhQx+TCOlbIdDyxTlQ=\n"
"ntor-onion-key-crosscert 1\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf54AXiKvFPzoVgDQ1tmyxJOZ/IboR1x/SB7rU7AHhAPfmQcAOrIvaG/xJqe\n"
- "adM6mai+FlV8Dbt6QrXTcNHJU1m+CUDthA9TPTAYz9D8W0mTEQ6KEAKGfQrNLy2r\n"
- "G1B+9wWSpA4=\n"
+ "AQoABstQAe+dOsVuwHoReGvLiYQuVdvTEgr7MOwyeK5dc6zd1mGiALA5bpkro0Qh\n"
+ "9tV7U1Ym6Pngmgs/Tx8yUzwGIoefT4A1L14yYokNBBe9DQ207rA5y9u9WnuT5mZH\n"
+ "2mcZOMGzywM=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
- "JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
- "M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
+ "WC79UXdGUGKTPFfB7Oz4qtk5uytmNA5XoCH4w9cpKOUBxG5Fc9Dol58STLr/AWoS\n"
+ "A9Gfx2zN5MoOyv34z2UlUV5Kp75zT8emxun47SqKv+lqRqRTtHrFavOkO0LbSRH3\n"
+ "bxYDdx/HmQnz48vQyK+VLm8lowsxCjgIBVmTKs93t3c=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
- "reject *:*\n"
- "router-sig-ed25519 abcdvEzGFYMcJ/Ea7sbessW1qRJmnNNo2Khkkl0rEEgtLX0b4L4MMhK/ktS52Y6jX3PRQWK5PZc6gjV7Jaldh+g0Aw\n"
+ "proto Link=5\n"
+ "router-sig-ed25519 DA5Fd5XeIyZWetlWbLRKUPBZ6MLW16/C3/m42sSMV5ya4MRMIql9keH/m7apzd6F8UqHztuHnFpgfOXwyN3OCQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "Vyj7g3eQ3K4+tm49fJkAtsAYnYHcEiMnlucYCEPeKojzYStNfZwQO2SG5gsoBIif\n"
- "urgQZ/heaF4uiGFg64UFw08doXqQkd5SHO3B4astslITvmq0jyaqzSXhdB5uUzvp\n"
- "QCR0fqGLVS1acUiqGbRr4PiZ9G7OJkm230N3rGdet+0=\n"
+ "aGvBliAHSDUmrFcHMLuEKQVFY+zr6oYKgJjBe2G0j3Xcw9VpwSpZkgmZa5jJI0br\n"
+ "HJwA0sd8NhzGuP9oCLbRI6pdT5l8TDCM+zM/G93Sz3cgxATj2bxDTg9/B4HNObCn\n"
+ "1VufCazt1ild43svRJa2bLsqWKTRHKA8LGKmwYsvlWI=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_RI_ED_BAD_SIG4[] =
+static const char EX_RI_BAD_IPV6_EXIT_POLICY[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AaEnncX/t0cbLm1xrtlUpkXghaA8fVuV7g1VF3YNfCaIAQAgBAC7Ki3S\n"
- "zzH9Aezz5X4fbwHeF+BQEDfVasfyTxTI4fhRi7t3RxHzBJd60uEMXy2FchD8VO5d\n"
- "j4Dl7R4btrohPVSVBQZuemBQSW6g3ufNl0txpFWu0R7vBPTFH6oyXYfY9gQ=\n"
+ "AQQABstQAUGR5G6d4pKIbn8TsRPUlzF3aG+bGlSRq5CmgY3FHvXCAQAgBADHVYAg\n"
+ "VsnLCsUgF4yKxR8mDyeVRASJ6Lan1xwA49u0MrcvHJDohop1C2fRi6npUKM+G80J\n"
+ "vebsEbexWjnaWURBrwx6YvvF22lw5TEc6dm8KxhGNOWSBFukr3tWJpn6ogA=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALGKwzhOui2/jJPjU1ngW5IZRPcoDk7RAfGDO4xaef4VfAFHCV9CQO1c\n"
- "/wQ09CcRdggTvUcv9hJTGJhSObUUooCkxw4/35f/A6/NoW1Gi0JqF9EsQWHpuAfr\n"
- "n/ATlJQ9oGdTCNDq/BXSPWXhoI6UhUe0wiD4P4x4QwaYHcZh+lE5AgMBAAE=\n"
+ "MIGJAoGBAMebdGK2Ac/1eewX+boQNlZA+msq7kCqqS3FM8GRBrCZGm4MFCx6bDZT\n"
+ "sMWjOqN3FGPjN49I4GYlgkqlcvgaKFB/DGbXOn7X1W8fa0qzKK7okK9qtHMAjINg\n"
+ "RjZ4aHWmeGhsVpGD1ifEEofWWjx7/T8dx7XIvNdu2zgKVjuySdGrAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 x1WAIFbJywrFIBeMisUfJg8nlUQEiei2p9ccAOPbtDI=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAOKrizVm2h5/jE/HqqLCBLWJZVVoGspasCtDDqHhSqsPzyjpqa52iMKi\n"
- "q/deJ92le3J2NJRGKxPmPQqWxwhIjnMS5kUMoW182iLpO/G9qyPZ0dh6jXB0NBLF\n"
- "ySfW6V2s3h4G4D2P+fqnsnzQnAX7YufkvgDau/qTWi2CqD0CjavDAgMBAAE=\n"
+ "MIGJAoGBAOFfyR3mbBZMu85gSrw/VBofkCmp8CwKU68pEWc3SL29c6LjV9LCXrDZ\n"
+ "08jUZ1RRHR8hYeLaz3ZxLhOQ50JYw55w6YhLbfzZS5+xt7gay6M2iFjj6vH8QPqc\n"
+ "T1zFNy0DAYID6u2AcvTGrRdRPv9NBs64wf2fJAGWUXNPQMlCIjKtAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key A9h8jY9dPbhHTDbIc/NYWXmRP65wwSMrkY1MN8dV3BM=\n"
- "ntor-onion-key-crosscert 1\n"
+ "ntor-onion-key 43r7FnWu5hrjSRXEIEGIOsja18U1+5/zMUDWqOlKSRc=\n"
+ "ntor-onion-key-crosscert 0\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55AbsqLdLPMf0B7PPlfh9vAd4X4FAQN9Vqx/JPFMjh+FGLAN8xr/w3KFVi\n"
- "yXoP/az6hIbJh0HYCwH8D1rPoQLcdpe8XVwFSrHGarZesdslIwc9dZa/D1dx3OGO\n"
- "UhJOrdv51QY=\n"
+ "AQoABstQAcdVgCBWycsKxSAXjIrFHyYPJ5VEBInotqfXHADj27QyAFEDwHRfJikw\n"
+ "3q2nD4w+XXQg5kk4g+pKuFaVSIbO1Xem9F2Hd+0JgiLlDSuAgLeUKiZIqGAm2Cil\n"
+ "vDw1Z+8kHAA=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "bLmdO7ME5vq+c9y/Hd8EyBviMBTeo85sHZF/z6Pehc3Wg3i1BJ8DHSd1cK24Pg48\n"
- "4WUrGTfonewuzJBDd3MLkKe6epXmvUgvuQN5wQszq1+u9ap/mRf6b3nEG0MHxMlO\n"
- "FLx5MBsScuo+Q+pwXZa8vPuKTtEjqbVZivdKExJuIX0=\n"
+ "LVjbq3IyLJSQ09ywgtPZ11ddpq6Mbldd7CsX7VAE66ihd5LMJmEVuugilHZqIvQW\n"
+ "JeXJylZWvqbwFEy4DDZCTZBh9aXUouZEIm3jNxyWDu5LKs9M/cKZTXcleWiipDue\n"
+ "yS72i2K2l9zPY+YoNMElc9TlC+lrOlpaT+fwR+93cWo=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- " router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "ipv6-policy kfdslfdfj sdjfk sdfjsdf\n"
+ "router-sig-ed25519 T9pQHeYGU9voVeSoywCtL62Ep2EyYSO7DWjwVOkLxQccAyBa3NS1sBaEVEPXyDtnXeZQUL2hCDy4kEulLimnDQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "LqNGEa10zwSPeomBXTfgvBnnWAdWyiR7KYZq9T++jK4ctR6hUaWngH8qSteUrkMx\n"
- "gyWb6UMmlxdfOG0sdcU463HsqV7zObaKya8/WwQ9elj3FfsToswUCeOaLR/Rg7wC\n"
- "zcUjI5VsneQoXT2WVZbZBLsLB3+7QfezVHRMB377GAY=\n"
+ "HDzaU7OdsTuFtjmHwqXkJ/+DCkTyz1vzd39F5L1x2dDZHqk0DJNHy5E6jWpN4yqF\n"
+ "m3nvoKS2II8r06NX7gloF67lfwTtEVc11HZWqyuzAQPZZj2VlPGH/vbTA1NL8MjM\n"
+ "Qn7yzykq8Ry+mLVJ4b1vtZOHm67K4q3V3pSBG5AKO68=\n"
"-----END SIGNATURE-----\n"
;
-
-static const char EX_RI_ED_BAD_CROSSCERT1[] =
+static const char EX_RI_BAD_FAMILY[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AV1AfOvQWKlWsbzoBdJc5m72ShIJuA8eNV15basjhXYdAQAgBABy+KQK\n"
- "3oLDGtqL5kwRmjAsls/+C6SAoAALll7U7wNSH7en5RVBal4RUzCf57ea/KG0c9V8\n"
- "2DmZ3PdOt2aY/M2bWGmmH/tyyapOoV98dhDwFU7zcx/pMfRnJTDRSDwl8QE=\n"
+ "AQQABstQAURbCqkJspCMD7ju6hc5A5b+nTEaKJ+Pay1TpF7nYZXhAQAgBADzX5sn\n"
+ "pjOeXa3eX/C9pVLjwtq5VRddbd7lf0JNlZ1ad3wtO0l5ETftHyU6QoA4g1ZU6itY\n"
+ "IQVLmIdvHo4nXMvUDPWvzEMZiD1epyNnVHglyJXMzC5dzUteE/Jdb0wx8gU=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMP6xbqbj+x1mq5XImjeT0rUzqKZTgBd5zvK4Xcy9IifJuFC9+mMzrY4\n"
- "WhYbdClxKUkDMkit9MVhek+P/w5TSHKl6AuqGaO09ID+hZpoUSdoBUYktynxfGsx\n"
- "kIDu0XvgtAeSyJaVvoV1SKVChY0IBbzUqbHt4O2Q1BhzFCKEJTEzAgMBAAE=\n"
+ "MIGJAoGBAMIwbAgXUtGKe8W2wsaJPqFz2cCaRZy+1ZHEpyMWSN69UDdl+QTEI5qI\n"
+ "W52+bXLXOCQOPLaFtSmfv6i09pPlb9XcyZCfI3W/01KgpKDWFji4QACK7BQCCxaZ\n"
+ "avKwo8eN0XSL5ihcPSZvSMFjX3AdAMLdtYdQVNpCg80NjmfHK1FfAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 81+bJ6Yznl2t3l/wvaVS48LauVUXXW3e5X9CTZWdWnc=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANwWlBh7e/eSLlhto5YUdj1iGYOq+yAmlosDItVfYrSPJuUfM2ocMBAn\n"
- "udbRbWiADoqsbKn/gwwHCC/f1HX2FkRXxxnOlJKLo+NEi8tGmOlcQXSQol1pCpvK\n"
- "sA9TxtYr+Ft4LRpxNrexF+pIBxqzwetqQrZbKYr0CFJi8q1qlMynAgMBAAE=\n"
+ "MIGJAoGBALNX/+fYN5lj6v7UqrK+URDxRBPnrMGCv79WZ7lfSc1yaxFPWqAG/OD1\n"
+ "X7Voqb5xhr5bsszliBe2m0DfOTOPTQ91SyjUoPEXznfHYkbwGVRhNKNa2eN7E1Sl\n"
+ "xw2iSoCnZEpKSaQsLvHvIaYiWnhvHtRl7QCuAym1I1hPPw+BTnkrAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key cs1AP+xF5cXTLuKeOeItdoDAzfALTJkwk9lB4mtC4QI=\n"
- "ntor-onion-key-crosscert 3\n"
+ "ntor-onion-key XjO8+6SaRrPblN+i3FftAlAR1SAij1e/Tlj6x2L6T3U=\n"
+ "ntor-onion-key-crosscert 1\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55AXL4pAregsMa2ovmTBGaMCyWz/4LpICgAAuWXtTvA1IfAKo6ANUq+hi+\n"
- "xb3J4aYafnszlj87oi/DR+SDf29wzwNw8gmaqGzJ5GbfISfABuTUCzlilZyVnLxi\n"
- "BHcCH6PWiAQ=\n"
+ "AQoABstQAfNfmyemM55drd5f8L2lUuPC2rlVF11t3uV/Qk2VnVp3AFoeOhW877qn\n"
+ "nmT9epNCicfIcyEynHC2865A0htIKT1CCRA6MFNnCMPIs9TpYU0G1zyrvdObtPsm\n"
+ "w+QHaRhFuwg=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "qC9Kph/kGtONR2DxZDoIFFgnDFC+/7H07EgCiYQdIFIROc+gGK9qBOgeFEptrkXF\n"
- "XdE35xxox5xSASQvp7hjFwxUtJRGOtf2O98regqeeaz6O9VPXHkLf51uqX3bVgq8\n"
- "KvFAsFFS66GxhtbrVjpyRgIwHAYvse1WVESfLuZZTn0=\n"
+ "q0Pp+duh37vyrIjY1gW+16ueGRoXOmFwILm9Eq/6zQedtnUrReTS4CqtkRvMTJp6\n"
+ "JeOOHWD4mcYdoC31NxaYhr/E7aafE/rzRZk0b5H5RgtixVdsrUUcFyWXLsYP+koC\n"
+ "pTk9g3nsOfQCF3u/p0nspsogkZd8qq4fLqyJDK4qh2s=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
+ "family aaaa,bbbb\n"
"reject *:*\n"
- "router-sig-ed25519 3uW8Q1aetIQLOsqSco128ZUaHlhqdYiBvrxV7x75BGNS5RzIMTEwYDNtEX1LNPFJ5N0YOV0HEEOLhrJUV9QCBA\n"
+ "router-sig-ed25519 h4sKEoqV2V/jvbP+AM8dEW7gyXWzMi5u680qa0k4VvgDwj8mkQG7NYguy2O5ovZX5wTE81b9pjNmR7Fx4Wm+Bw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "WuD7S/saTYBxKvItITbHRi8n+e6g/oVbosicfbRbafYPzPp4Prb+RK03UTafzXrV\n"
- "QEQIzDNhfePcIMH8qX+qrogLMXFqiXx6TVQ0GqNvqirokk8ar3AgtRtewhChAuAj\n"
- "8pmQTj2JpZn/iB3PCE2l/93O9LHZfp44hc8QOWKs6BE=\n"
+ "qEFvYELbbiKjTnXxmbYZDHdeEDIAJrIhxbgLfTFKI6LlOQ+sy5XGd+fCU365U6Mu\n"
+ "0jOej6XL1XQaHE1tFhviGj1pNLlaKL3xK/VDLNhjJSR20adtOQo7UX5NutWhQdSv\n"
+ "L8k5Kqc43XXhqQrMC2nKdFAF43mcp3MesBAnkJVFBqw=\n"
"-----END SIGNATURE-----\n"
- "\n"
- "\n"
- "\n"
;
-static const char EX_RI_ED_BAD_CROSSCERT4[] =
- "router fred 127.0.0.1 9001 0 9002\n"
+static const char EX_RI_ZERO_ORPORT[] =
+ "router fred 127.0.0.1 0 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AW5TTGF9jCMl7aALZzqypD9Bj8WYnAPIrKCoIJdgMbY0AQAgBAB7eCn8\n"
- "rukx7t/egZUdqU7+FYqsnO4wdmOkLZkp0+gpF3jjk6N1Q0037NNVNZBjONB0Nm2F\n"
- "CpB3nWSJliSSKr5tOYsuBPFy5VVGYeKPakpOoxanQ1UcqevMBAQy0zf9hwA=\n"
+ "AQQABstQAUmwuikZ7vHosMBCYuyHaTxtFLZstIlPgiR7CYZNyfC6AQAgBABYaoui\n"
+ "ahSEC4liv03C91ZzmpKPUy09X9nOUYgRtb+rsJ6/GklBLyC1pX7YGiCbUfnRcIXE\n"
+ "PRaFkYvku9qdIvj8Zxf+dxPLOQbuNbR7Ky2oLVgLJnC65N5tzoqcN7axWgY=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBALeS5YbeDuKQ5iiuUvh3REoyJ47/YU9lslWmTrVBf9b66pMnYJv/awPu\n"
- "m2HredUAJ3VzwQ38VJA39w3fQXUhQDnQ0OPpKzeAmIiuG+6WdW/mBSK7uKcezC23\n"
- "LA1d6Afyl79LjZz/n+ENXqNMlJk4QPcPHuRnAvwBl3t8YVRPJmxhAgMBAAE=\n"
+ "MIGJAoGBALbQl2VvUsDYFiqLWZdJI5w44z8mmtrDyYC2in84CI7NmBqrqODyVDDV\n"
+ "xU7ZJtIfzmBFiN+oxl3Xja+p2UeZ2qhaPxNwBvpkj3uLoyqjrzxRvzrXOILxrJq0\n"
+ "zsVU6F9J4PD8khEK472XsnEwmY5wK1cVNm/n6eodGppqQbjMal6XAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 WGqLomoUhAuJYr9NwvdWc5qSj1MtPV/ZzlGIEbW/q7A=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAPprokY7utWuO/0252dBB5MCxmVD/dROaIBDyFtpdH+YVv04rkOlDzYD\n"
- "W4mgHVBMxEm/cspTgQmJ4exRHJPpcSe1RYHt1ONZdLYr6D7OOWf0y1IUrVSzF6K4\n"
- "lqlmNuH1H4+TKGbkvixYc5GU/2ZmAy6gFEuphYnBbsN2Ywc38mnfAgMBAAE=\n"
+ "MIGJAoGBAJ71N74R9kO7XgyH0CH2Z4qtr2YKwu+U4FCgBZozMoBe+vcynzNNXRMR\n"
+ "UOKl+hD5nl6CjDO+1Q36iUJPu873CzZv6SXsICnMIkFx/nrMD8JGEiqupjj8H4SS\n"
+ "t3hRhlU6pStjwhqqJozUVinJ+CKCwHG9UnUBGiPNRAwAPU+2VVcHAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key Cgo6xniGfEiuYoLSPUdE4Vb2D4zj2NQzC1lRjysRRXs=\n"
+ "ntor-onion-key 6qko2boqKfkcENCGbCSZ1RbZN3TY2AFqo5WMFnwioC8=\n"
"ntor-onion-key-crosscert 1\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
- "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
- "mjQFK4AtRwg=\n"
+ "AQoABstQAVhqi6JqFIQLiWK/TcL3VnOako9TLT1f2c5RiBG1v6uwAIB8Iig7LEAU\n"
+ "CcznIarqADUWZK/MjxQZHoCdVmb3DlVZ86BWnulrjUnFPINqBRsM1m7a92AHJI28\n"
+ "SdQ+PEw5VAs=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "bi4M/AJLZF7/vSNmOj4uhrgKBQA/KfcZy5e58mhGL4owxd9vaWfl3aelvb9jf9zN\n"
- "Q7FMv8f9aXzeVIoXIpRJxSKIJgBtG2wnMumIc80pqBvTyGInharszb6njfm0bg1u\n"
- "PfJkbQYyf/dA5l5UwCrjFs06ImDmjFTAdsSWf6DfZ/k=\n"
+ "VAzikUKMdtT0ejXQ9XjA0IFKYyJK3LUpwYRx5jHupvpM9pMww1UpVORwEySOuu/l\n"
+ "iWy+YT2BJ1T1gybHO/BUbMUOCJs746wKaRu1TNoa0iB5hBS08eZHsLcuMPWNj4HZ\n"
+ "8ul4kp0JL6s3SwCyHPx+3ZiXWlAlyixIMwYMYp3iUwA=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "router-sig-ed25519 wYbZMmEuVaKbcQVwPDuNfqoowIUQB2AXmLhuZn7x7c7Le1K6GJvGxUP51xamZNJtPZpb3B2hY0Q8x+gk5JI9CA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "io16v+e0pK3sbFzPGnkQrAjrRgIOJHrVZ1RXcxZ1+UNXagWM/MOLhQpkU/cw49Wd\n"
- "4rQeZD3JQh16330eXbxc97AyDgp0b30He846SI0MfW/DnmGI8ZNeYfLbMv2bmbs9\n"
- "QULzyIH8C+5mnMI1arcuiAua+Dpa34F79vgqPuvw5fU=\n"
+ "tiwHHQTe0A/QpY6oom3lG7CbFvTtd9KfAyHN8kZAxo/mctogQw3ZBZbUFZWhrQhl\n"
+ "L57BcL/UgaAAtl7eD3X/91uaoEZl/avxlmvgTEg59aQnBzhAkhj/ZYOjQqTTlfWS\n"
+ "fv8wOQgiuJSKTBBY2LZAJyMDj0oI7PK2JYBtnUvi27A=\n"
"-----END SIGNATURE-----\n"
- "\n"
- "\n"
;
-static const char EX_RI_ED_BAD_CROSSCERT3[] =
+static const char EX_RI_ED_MISSING_CROSSCERT[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AVB+j+B2yPgGywvp7nvejyhMh9ejKmw7LCwufV83Zl9eAQAgBAConA3B\n"
- "jJ3X2tES40jd94rRUFS2/s/Yv7E4LEQ9z0+jz8horNivzK3O/t7IGxJggi+b41/9\n"
- "Uaqt+wqtVuKj0xJ9jwBlCXFt28G2P9s4ZyXYgGZqo7MlJlboybnOMvmoTQA=\n"
+ "AQQABstQAbLkl65prybuOHnQxRi+wVzjNlEsViHPH/T6RWQHtNaIAQAgBAAEVy+i\n"
+ "zeBNENBHHpiag6H+8XDe77msq4YHvxeycWRuJjjNnEcLLQMbtnNFmgzKWwGT2uPj\n"
+ "+U3Z9Rg0+PRkXHKnJKZJLYrglWHjQdiFELn8opGTNX3rkd/FdU9Ws/Fliws=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAPWuEWckT4aYAVNrZzLA8xVwfXp0wzfXeTWBztLS8VzssN6w/+cwXdeY\n"
- "N1YNc2DiD3u8f+7kmuZIqL1EFQUwTvRwEzQXm2dqGM7qkm5ZGNMb5FKu+QwO2ImI\n"
- "FLNiO5zO/LqP3cf/2L8/DuvruLenUrhRtecGFaHmhDYl+2brHIiPAgMBAAE=\n"
+ "MIGJAoGBANyNH7TLjpmgV1TTkT716iNp9tpZHwDHoYWduoiZntmDHpRN4rp0AdhD\n"
+ "LQ5/JEdW/XjAhcnynzINgvGw1nK2XiC/UdTv/Gx6/6Nt9Izn7oAT5YRUOOUaBDYm\n"
+ "9Q8uNo8d/4FrXDEsxaMJme88v2Z6LJd8FozBwlkfeTKdOJon6IabAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 BFcvos3gTRDQRx6YmoOh/vFw3u+5rKuGB78XsnFkbiY=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMtHTfk0gDvp9+PtIG8Ks7rgCiJZ2aihSvr6WaKHYuIprgspFuga98cg\n"
- "D//J80CrgH5Dw68YnkG+gU40IxP7YzhQ4glFlJGu3s2y7Qazcv5ww1XtHur+GDoA\n"
- "cY0zCLhltNQFxIsoVUepY97XA6Y2ejYJjyqNXQcAmoPNoVhnTdkhAgMBAAE=\n"
+ "MIGJAoGBAKT6X+Qm7moNEV7o0oAcrbzpOa0UyOkqWxQkfijqcMbreuMXvfLyBB9l\n"
+ "dgttee0cf0LmWWv9nBtwlbQNgFzkOwcvPRQZ2e1AiFsk/bFlQ5Ow9nxRJoUboL/r\n"
+ "9VCaflE+ETtV+fTl5R1sn3j3OsxK8SOhOl5s+6OAisp3wEaVhjVTAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key ibZf57LptdOK3WpVFXkYMatEEqPhuVWxsnkwF6638V4=\n"
+ "ntor-onion-key DqsbD32Vw56RVM6+gdrE3x0b3DqBsuMsbwOpzYPSB2k=\n"
"ntor-onion-key-crosscert 0\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55AaicDcGMndfa0RLjSN33itFQVLb+z9i/sTgsRD3PT6PPAEbkxCdI/bH/\n"
- "B06DAjRuoDiv1HKsGuW+UN1iGEiWu2ieFzf3m0Z7BL9p2u2zIbHYkP50b3T3sebD\n"
- "1AksemmMdA0=\n"
+ "AQoABstQAQRXL6LN4E0Q0EcemJqDof7xcN7vuayrhge/F7JxZG4mAHlxXgoRkCMR\n"
+ "QRUsroTKgpVFI6FasFLpfbn1PNzhBwrA0x2Jf5VftmgraI40+oLxL9SiMGzakBfJ\n"
+ "FRXjeMEk2AU=\n"
"-----END ED25519 CERT-----\n"
- "onion-key-crosscert\n"
- "-----BEGIN CROSSCERT-----\n"
- "BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
- "JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
- "M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
- "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 XS4zVi46Xl3xKhuozPCDlW0QRFD4qUhJmkefonQNsRlMVsrPkALnP2tfnfdfTc69hbNa22pOjJNf6Gm505EnAw\n"
+ "router-sig-ed25519 Dxt546uUdpCxCbO21HaaA6JtW70Xsx5evw9l2eVlWpGDzCTfGO4cMlIUku4ABQdrT6wk3Er9qL5paNyhrYjfBQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "Q+R3OpO8VhfvFbXuE5qolhVbgosBHy2A5QS91TMzCbsxa8pBA6Li4QdPR37wvdLq\n"
- "KayfmmNCMKU5qiZMyXqJZm4fdpxiSi50Z0tYlXM3b2OVfza3+pSOEBl89fN6G4Qc\n"
- "pAmM14eEo1UzXrqZw76tMS2CwOYF5vR2xFGCYC0b5hM=\n"
+ "ik0LYc81zprhK5GN0SxE1ikzF+sAzCjo2vhFsihljOyg3d9XxhbriTpROJeUe8Ig\n"
+ "PpgLPeJxPFOvs5jC2XeTAOpxdYyMqC7d/RfupG2v9qBzcj9a84p+tOP1DZKg9snn\n"
+ "NZS6fGWijh+okwRlvbFPk9e4Z6gJUSLthTUhz6P8/LA=\n"
"-----END SIGNATURE-----\n"
- "\n"
- "\n"
- "\n"
;
-static const char EX_RI_ED_BAD_CROSSCERT5[] =
+static const char EX_RI_ED_MISSING_CROSSCERT2[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AaCfOaispi7dJhK0c8HXJHIwoBkMgRpmmHu+3Zce/soMAQAgBAB5bAIo\n"
- "5i4TSY/bV2KQAyziRwvgJm+nEiECClflPbP9Um+zOzOgxtDmNnR5UFQj+VWNG4uf\n"
- "5lnaryN+PfUXZMTcs8AARof3fFz9tVPINHDrsGvKt8gpzgZEHkVioAXOFwg=\n"
+ "AQQABstQAXpNZkKl/K3IRSQvhjsdeSGChzvAux17KOfhfmTGqNXIAQAgBADG8kM5\n"
+ "+9iJxF/Hf2jvvpiZddN8V4RPcJH5i3tIsekmwsaoy3FMnMisGFsOFUjxtSRLmAM5\n"
+ "EtGNJayNNny0qDRo6o/LxmXhl7fVxQPnyFEPjSn93cLWVV6/0LjYaYHUsAo=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAL3Fr/ovZ9SMGYrAM24taKBm/NpemZaXdD/JeBXFYm5Zs3szLwJC4Etm\n"
- "zjNL6tVy+I21O1g3cs16TkflcidsjPXNx//PHAn7bqWMekjrt3SQdkHW2gDPgT2c\n"
- "zYJ/hBR96JYG796jP3pkfJz6Iz5uT/ci3A/cdaVbzM1uZbMUgYGzAgMBAAE=\n"
+ "MIGJAoGBALJTSfgKFoMA5o4dDduwgwHfjU2KE3rZ430TGK9xhBFrum2wG8ct4my7\n"
+ "LS/EbTtxhQjNSrW3D1loThQH7H//cjjrtZyFs4cKwIimpnkRWpQzDtjSUF9vwAGZ\n"
+ "nUPuStPG/hBvJROVUmHV15nAgi+bWigEtXrNCPlpGaojBBIqDRAjAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 xvJDOfvYicRfx39o776YmXXTfFeET3CR+Yt7SLHpJsI=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMHB+1dWa8BBrKE94vTqfbkSEuysG5LyyZF/WrqHq/3W+ocDLz795k8O\n"
- "2Zvgr9im/Ib4hD7IyrtRexcuBdwujdG7cBALdCcWiUTGAMkl96HNETSX+lUVIpJ9\n"
- "pMsc9O7+yz+/0Cl2RpILZCdE/7I96qHpZl3tzlRKSu15WeIm5U77AgMBAAE=\n"
+ "MIGJAoGBAMXYiBXNlbvmWAM3tVe2fC7fazqaQzsXLH39QRhPE2DyldBdsmf8anc9\n"
+ "0rbY8uS/O5WNqc0KK0wivSt8zDLxfkw9GFM3WKgvdiqvRkmpOs5GDvzRdM/yGRNc\n"
+ "gCUBe9q/pE6LQJqoWx6cCcLKGG9Ga8c4WB0ttpiVc3cfoFXEz1RbAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key GXi0a2VLcRHQMMYys85zu3IPqOn5ZTsOixYyQvTGnQs=\n"
- "ntor-onion-key-crosscert 1\n"
- "-----BEGIN BUTTERED CRUMPET-----\n"
- "AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
- "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
- "mjQFK4AtRwg=\n"
- "-----END BUTTERED CRUMPET-----\n"
+ "ntor-onion-key N+jVTn3dmb40NOrpkFGvGTskcX6mGPp7uruGdhIlMXk=\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "T9NHMBhuJo+TlfU3TztNgCc9fK1naNRwPOyoqr5R6lJvJ40jkHnIVOFuvuzvZ35O\n"
- "QgPbyFcMjv6leV5xcW+/I9tWaBUFXiRGI27qjCFth4Gxq2B6B2dIcQliLXSvW9b+\n"
- "CMTgDwVa4h2R2PMh18TRx1596ywE09YhCgBF3CwYsiM=\n"
+ "Cnbs898bRLOgjytkt2bzfJmewumRwscGqXDMG10y9QtU+MuZuTl+Mv0w/GmlJG0v\n"
+ "H8ECNQhv642hJOBOuiS1huF4dW2lEhFm+xh0LaxaGFFvJRtuH6NfWDmI1bhN5zbK\n"
+ "RqKeu6QamghmtcwiEym4M1fPPkGbOY2nwJhhEEZOQCg=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 sRpiP9kyW/DGOphp4V2VCtcKNA8i7zGuv2tnljNIPTB7r7KsTvdUk/Ha9ArRQEivO4nC2HHENtknDl3GtWIPCA\n"
+ "router-sig-ed25519 nZA7TcgGlFa64ZViIMqIVNP3d9C6XGY+5so6Ll2Yeu31N6MdIbwrYL99nfCkfwyD2islcHl0kp45c3ZZrkmQDg\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "DtORw3+gO/yUUIp70xDaWSOgQZrJAAoZTNCB7q5WCoZOngeaCiC1Gtc+Fmdn7tER\n"
- "uPqQC5H/Kh3Mi82PCj0JxvNivnNTNY1AZVaIX5YoioXVOkWF0B2pqMvFuDSdm2oJ\n"
- "29PqSVcklquu19EjJRTopIHvYn3sFhQL4LarMsYY11c=\n"
+ "gD19cH/jeIsTBAjds6FflLMXw++Ix9MoWEfFDPAxbD07rdjtU9x6Z9smDAUG29/v\n"
+ "bWvaQPz7mD62IVu/IxINEVOS7vGrSbgvFKzUm9a3FJiQf8oWfHrNE2PNPAZ8GCgF\n"
+ "sdyo0rXyPgMkuW5ZtxDxejaybzVBkIbpADFkJI3B210=\n"
"-----END SIGNATURE-----\n"
- "\n"
- "\n"
- "\n"
;
-static const char EX_RI_ED_BAD_CROSSCERT6[] =
+static const char EX_RI_ED_MISSING_CROSSCERT_SIGN[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55ARMMCtQ8pObC5bq02AUE9Lx2bqsZBBkeOsDZVaEq6JavAQAgBABtV0xF\n"
- "CsWXL/uFIBnoEsnXBeU1MvYRFrj1vR7QHdWXnxywXvBYUAC8lu/uyc8qqLp+aQSJ\n"
- "5JzpDYlg3hp1fl5k97iv5F9WrR6s554YpmgYy9agFaxZ4LmRgz7n0UJ8mwM=\n"
+ "AQQABstQAY4Q/FgXCRTVdPYd+7V5rMNtz2yUwCCUHXzduBIWfmbjAQAgBADwQyw5\n"
+ "OWRsl2fz/uGjbzBhT/2AqRNTZCZ1oIR/Lf8ZhY/JbQRCrYwMqMfJz6AHaOJ+gYE9\n"
+ "Z/ooJfYDXMkhBufAy6pgq5HQKKPY9f4drPGrcspQSilJYNsc7xdaPKHfAwk=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAO5qd1TndKD2pEs1ZLWsHlvfO/E7cA0H7NKGLSioGpBf4P0rtkueX4ci\n"
- "kJNa/4Fn/QsLECqEF2lUjkIc8YL+HMS6qteKvN8+nn16DfvnIhPDNZWTJjLl1bOI\n"
- "sWSSiduhanoWQnhRtl3Rxg3opdNd9ApO0DLUNy4Qy18Ai6SgksfHAgMBAAE=\n"
+ "MIGJAoGBAMk3FKSQ9eH4MipJoEzJ8ts3ujO8ed1YutjfFuRZVI658MX1ra9wZdjs\n"
+ "bKfICz0CoT3uJMs5QesGh75r1iXZuFcLq6+WJq/kzI2cIhdDRMQsP48kbKxhwI4C\n"
+ "FkDtK8urxS7Qpq7R2OhLjJwwrN2BcWa8sIOVXZaSp8qxauE11OoVAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 8EMsOTlkbJdn8/7ho28wYU/9gKkTU2QmdaCEfy3/GYU=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAJkMYNpK7eJJyGwD/xG/iNg6gzzbIwrOSvmtoP7Rot42qtBiQ9A9kdsy\n"
- "sazwkWkM93U1+1OaAADPYxeHoyHnuia95Cnc5y2lFSH3I7gnGGSPKSTwXtdyvDWZ\n"
- "P1LbmQ4Bnh5leTCNZ/eFC4/GjNVzqHxjbb8a11dQhA8dOk8PrUq9AgMBAAE=\n"
+ "MIGJAoGBAMGSYXKAwFsZbEbRjiHyGoiiq6EdY0tW9hrmW1ma1nMaIoNbjpR1AVOh\n"
+ "ItYigmRi9zwLZy1b/P9Q8dlazdafc0bb+TISwu+4Cd8BKa7Ca2B43JAR1i7StxpT\n"
+ "DMw5/QqrFw7hiTrFN3K1RVH3ZDMyCD+KjjfQh0RM9ytf3ySniUDFAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key HdSQOqvLr4YnJE1XzzVIddgKgnjaHKJqnq0GqF4wXDg=\n"
- "ntor-onion-key-crosscert 0\n"
+ "ntor-onion-key t1Ps5TqoFvAJxqCLMUcuoovr8Nq2AzwjDPB49Mi48SA=\n"
+ "ntor-onion-key-crosscert\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55AW1XTEUKxZcv+4UgGegSydcF5TUy9hEWuPW9HtAd1ZefACVwif1deQry\n"
- "K5GeemRa32sGzujVDDe75WRiPKFT3l/EtjTq3oeVq2xwbVJklnG3ASejKTr3YcHt\n"
- "ov0jOl0jywc=\n"
+ "AQoABstQAfBDLDk5ZGyXZ/P+4aNvMGFP/YCpE1NkJnWghH8t/xmFAIQzKPwLjOWJ\n"
+ "VnP514SdbuwehSRrkUMxBSqDxzsDyC5pUCqJhrj3EuXDAMeW5Hz5ukuimdIJyvPu\n"
+ "2cLXN/1Emg4=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
- "-----BEGIN NAUGHTY MARMOSET-----\n"
- "BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
- "JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
- "M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
- "-----END NAUGHTY MARMOSET-----\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "SaVwgM+jd1yrKldHqi8XalnXOplkBHFOn6AXtxDlCm4rnsb3Spt0006nErCDJJQn\n"
+ "xWkcz3mF2g3Hdf6NeSvAkH13SfqZbHZXQeYVtQHrmIF7TEHL6KHVNJD8ZxIoe0xp\n"
+ "IawxfHSj3FHheiVvXGamM/7fpWyoNvYP3cnZJv6zqCo=\n"
+ "-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 lNY8TRX/FZdH5eFbsBkFHuRi8bPDsE5P+v7zExyD/IXnKS/ffYlP8qw1XIPdEDOIzGQ14+kyPX0SotaAqHRtBA\n"
+ "router-sig-ed25519 f/KOmiv/aPMOnY3S4sKQsnp08KBrQVCT443ehtvYtiTnaSuxUC5tYY4S4rbQaGjNRFNX1Befwi4OvJ3dLFTtCA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "BHamS+epF77iozo5cBt+tbs22m9GhwY55DRXpEWAtvn67jsMnmn7qCOLONigK1RT\n"
- "adZNezIydcCxXltgHTdKaZw4lcqv3s0KL8kI8frbBmm7PjXtWnrdXBYY+YK54MN/\n"
- "t4N3162o9hzzKSwye0gPjgzpQ1xtEIkzWhBcmE9Vw5s=\n"
+ "JtCuaAENvHhc1tLTI9kkUsRne/OlEeIgB6f+BqMIbxWDpmiw2SHTbYVx6TbKZ2wU\n"
+ "qR3R7SvapeGUIfoVhvVEzxExYTRvFvF/ICDs5vve1aoWilrFstpXsMcL5tG5+ljm\n"
+ "cGJ5PNsTJXrlOy7p/UEHyvgqWcMKxMRBjgMe6je5w7w=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_RI_ED_BAD_CROSSCERT7[] =
+static const char EX_RI_ED_BAD_SIG1[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AfVmH2ReTyatl4VnS5YREtCM2dwikWuAPffq6M5bysZxAQAgBAAXoqE7\n"
- "taqwLDXLZrZukpF1eBkCwYQK9uzctHTuMdqOHChguvkfX7V4H3O76Ayqvz+Z1ut1\n"
- "KYRdgiArn3viRaBv3ZKT4Z75suMI3bjqGOSGLAKfOa0uLkOmKblHHhSUkwQ=\n"
+ "AQQABstQARhWF2mKrRP75a4g/xPp+fAkIlyKgZa5rKIzGZJiABheAQAgBAB8rr8g\n"
+ "E3MaKYmA93baIS0pvM2tjjeozZTQVzCrP2PykhNcs24ytb7LHgquweVH71Pk3Ltf\n"
+ "Dvl/2MoSFelmOjq4ikrLjntVmnIO1a3aNpt8XmeqjrVg3pBlXqdLdloedQI=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAOLNugzUezzzw+N1SuQWzILJYkUJyQDoVXSZjT0dzBplHCjlrv0WZCUP\n"
- "/pbonE7SlCChIovHcdiASaLj7MVaGgYDq3M1Vtgt5vhgGl10/+evBAD1QEt8AVfr\n"
- "5+PH/sbZvOWucAhNUhOlqFKAn4vdRY39VEEXC5/Jz5fsk1E/DBu5AgMBAAE=\n"
+ "MIGJAoGBAMnGnWWnyF3uo3aFhiph4x2i6yjnHC6ssgDsDR1UA0dUZ7938LcOMPU/\n"
+ "WWUQP50kRx3l7lWPRd3IBm8Xqkg5QFKIoB+0UmHp6jqpVv6p10EyJ7Am0SYcswre\n"
+ "vIZzz6XLEAVeeKVBW5p53KrzIhi8cjbOIofUspcBlHX9omB6Va2nAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 fK6/IBNzGimJgPd22iEtKbzNrY43qM2U0Fcwqz9j8pI=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKxzg1hsYMS+0zAIrgYxSGO0GbKRrL/VhdlMEGu7ACaoqlGnmGQS3B4B\n"
- "gLk8xDdx9N//8+YTx0hUIxP38w08lubPl1WXMq8s7wAiFd06Nklf65mHs0sXVtS1\n"
- "EG3f97PQqmBpEJOwYBATNcA9e6F62P8SXNkpSjOzNaE0h9wHNKk7AgMBAAE=\n"
+ "MIGJAoGBAMy673ilZFIPOsfMdt1sNYFw9Na/UoOGH8peXmGp5gpFpkJSHamZpqGj\n"
+ "8OdW+KVU2/WzS96fEQ01wC1IiXwcjUtrD6Ny2JKJPARxPADQ31hS67z7gDVjJe9Q\n"
+ "vFzYBf5x3aBKjKHbFMUz7y4L1IeBYfb+F5RBg6yrDA6LsPKKhJdRAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key msdr3O4W4bm/xdmZLzj35363ZSFex8yQxLWsV3wRCAQ=\n"
+ "ntor-onion-key /7ar3nf3rOfiv8Ab01rqVT/ku2jiWZgHHMGW14GPhTs=\n"
"ntor-onion-key-crosscert 1\n"
"-----BEGIN ED25519 CERT-----\n"
- "VQoABx54AU3MlHAEtgPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
- "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
- "mjQFK4AtRwg=\n"
+ "AQoABstQAXyuvyATcxopiYD3dtohLSm8za2ON6jNlNBXMKs/Y/KSAFcBPlSKXOxY\n"
+ "F25sS5nNj58Z13bBW/WnQ7Dq0kYvS4o80iO4ds91ktwMZiiadfVu2az6tjNRb5+o\n"
+ "iShsVStqfw8=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "RJJRiU0vjVtRi3bVZru3aTvV5l56X/WOOp/ii316yPAS3aAMpOm1+piFVR5MNqcB\n"
- "ZGyrA2Kx0hawdL2buU47iZ12GOCi4f1Es4V4N0TQgJICsKX38DsRdct9c1qMcqpp\n"
- "1aENSRuaw0szTIr9OgR7/8stqR5c3iF1H5fOhmTi6xM=\n"
+ "TnfcFWCbg72d4tlGSFpe/FATTeRcJVF2R+c6/d86lyPwntkdF6eEJDesEFW2Leil\n"
+ "CQP9eJMiBbaEXU7xcMn9irguQl211lZj3+G47XUFNlORU+HWAR5PNeXj6jSGK89Y\n"
+ "SIduafU14iKNUy2fzAFZooem+OzzDwMKIxTUTiqItfg=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dg\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "F3ZqvsyL6RRhPEnNFFIZY4WJM7LK082rseWzRkGNXjwoEwOWUK8enQ4Wjit+wozW\n"
- "4HVIY1F+vP7gm6IiOEAFgEpB4C8FGuyoFw2q0ONA2tqTcvBJDDnqbx08FO7v2Dij\n"
- "d3ucfc5gf7YNaoFCMMuyAzC56eyNk4U+6cSKy6wnJds=\n"
+ "p0PBLzGrU5B4BIwcVcTiJCsSdnWcglG2urJuOSWh2tHx0lWIg5kPUX+WGMh/xarE\n"
+ "0X7xQt6amBZxkL/d70RM222CHg4IwXhRAV1qotY9cBNDKS6nop1Pkx1HOCqmsldy\n"
+ "VSmLG15Igt/y0aYvxPhVDfPUK1UmLH7eYKA7lKOCAbs=\n"
"-----END SIGNATURE-----\n"
;
-
-static const char EX_RI_ED_MISPLACED1[] =
+static const char EX_RI_ED_BAD_SIG2[] =
"router fred 127.0.0.1 9001 0 9002\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKT6OIN6TsDB+xcp1uLeE0K3aiHGqa7hdxMBGpvcD0UFSyzpVv1A/fJa\n"
- "tClDCwTpfTGbyK2L7AO75Ci0c7jf6Pq+V7L6R7o12g6WBTMrgsceC4YqXSKpXNhi\n"
- "oudJyPfVzBfKcJUSynv89FUQOyul/WRRqWTfv0xUsJ3yjuOESfCNAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AbBV9NVz0Hdl0Uiv87LiXaTAoeSXE+bheNG4Dju1GzQHAQAgBAD16h+T\n"
- "ygzSgPN4Qat5ITthvm+lvMwMVGbVNWMxNy9i33NGhgp8kqMp2iPAY+LhX8It2b+X\n"
- "8H9cBmYLO5G7AlMPj7GsuWdCdP/M/ldMvFfznlqeE3pCpRas6W48CFJ+9Ao=\n"
+ "AQQABstQAWoTtIdIR0KUNFswr/4eaP/cjngCX15TLiYqCH9qtCSHAQAgBAATcxt4\n"
+ "jNZlgrlMe5Ide4pmPN3MkpkrXFa9ZjIWjFZs/TC7Lg8D70xjvWo9l9GlIMUVcMYV\n"
+ "fWvzlrzTByup2wz9etZfpP4BfuFXgPlQyTHyANTQlEMzlXnA28lD1y8DZg0=\n"
"-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL3cADWgf3FVXZvBxRY9dkgCCSy9kcbk0bTbdvvhJSWHpaerpDFTrHou\n"
+ "ELWhGyu5A5yxs9YvK76R6v3Gj/wB/mIhZCJSViTSoyZnBNb0szfJVVyf1/6iOeVH\n"
+ "jtKj3B3kY/WzNVX246lVC2M47F/TmZ2n4TLE2avcnRQjAtULDQk/AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 E3MbeIzWZYK5THuSHXuKZjzdzJKZK1xWvWYyFoxWbP0=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANMO/MepK3uCkKTLRCwIWc/8URVza2gEmDx6mDTJIB/Mw8U8VRDuu4iJ\n"
- "v+LL3D8/HGLvT9a8OXbl5525Zszt8XueF3uePBF0Qp0fjGBL8GFqmrmFe6plurPJ\n"
- "TfrS/m3q+KhXAUowmghciVGDY0kMiDG9X/t/zKLMKWVDYRZk+fupAgMBAAE=\n"
+ "MIGJAoGBAL0Gax09X2sIcIQrDw9mjLVeVHnXEhMteHZtadDkXZJMjdJJaurt55hw\n"
+ "N01apm2qXB9nyUn5sShBadzygFTZzFHe1/MafUTAo7KUdJrpWZr8mBbxWFRBx0W/\n"
+ "OE2Gm1LqIETkeolT+v8LW6VvMPLyexL6myQCGB6yfa6AQkWi335bAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key I8yDO62Flx5O/QsFvgb2ArIRqwJLWetHMeZdxngRl2A=\n"
- "ntor-onion-key-crosscert 1\n"
+ "ntor-onion-key XI8YQWjxy6mxUIPwgS+ZP8GURSEw0r1IgbbOvYNLz2o=\n"
+ "ntor-onion-key-crosscert 0\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55AfXqH5PKDNKA83hBq3khO2G+b6W8zAxUZtU1YzE3L2LfAGC1uXxN2KwW\n"
- "w4PqRidM1UPZ5jVOHceZYNQcTzzzArfBpr9OraOO2up4TGte8GVqjJNxrZc1gfjn\n"
- "CwPW5WxpFg0=\n"
+ "AQoABstQARNzG3iM1mWCuUx7kh17imY83cySmStcVr1mMhaMVmz9AN7rBobY682w\n"
+ "ItzgJHnDFJv32kjQGc3eKRpZ851GsF/Jj7WXSnLa1oLaLmfFf5tgAKlA3Mi4jUzE\n"
+ "JQCy7jvAygc=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "jLg3D3VO4i0sN8p2qtB6+5C3tai/K4M89mP7z2abQnUTbynOacPoNXIk4o64DjBJ\n"
- "kaR42yfA7yQZ8Rj8abwgz0Zz6zbd+JjE+s/EklrEEtOl+jZAl3i+92FaHROJojXq\n"
- "hw+ZEPOb9zgb1UQ7S1Fo+GoqA5bdGm/Wg1kSQielkNE=\n"
+ "KxfRSdISHvFhJrKQX018NEb4rtZBZUgdrvaYWjazMkYz4o361wTOxD6lP3azblf9\n"
+ "IqhiXydwCRA7Akye7+muib7JzxSm3wX5iJknRrt8DY141pViMaMvrwXEAqEFyB6b\n"
+ "M/dYGQwUW2iYMkoQ6difHkDQihebE9lgl/WCmq4nRQs=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 TRKvIl/wIIRD4Xcmd6HYmy7tD0KhVGgoStpWPtX0zmXGZ7+jugItrY0frDu9n82syiruuA45ZOs1Rfi4CbOSCg\n"
+ "router-sig-ed25519 XheVxa1Z1HTviM/peYPSAB04YBivv+4v6/HGZ/K4UbEhKTrjSLcvdLG80vP6Owv8676A5al43MLMprjGn7tF6Cg\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "NYpRfurB1YhFmDAdRc2Sd77S7By2V/0kgEHpJhtySb7efiQsyOA4ZBr1zEFPAXdp\n"
- "TviKzyS9kN2fnz3hORoqFul33BDZbiLMNLtt5tzp62TYtmIg9IZdjjczbJUgbVLt\n"
- "KCJL0vM7fdbXkZX61GIBbMYwzwIiHvVxG7F/AS5RbtE=\n"
+ "j9qheDodbn9NZ1S61hjo9aCdHQgRrOqlEYrCMDv8LsMQU1LK6UjmszRxh1q9Hu6V\n"
+ "v7/qGUrsQLjg1Lfdw4qXQYmxTiWnleyncLnxn0Xd5I/S46SCsLoewgGN9uJ6gS/j\n"
+ "UdOEhvT7ShgNSemx9SpRriMKKqTuTQxRmZynr5ibvvw=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_RI_ED_MISPLACED2[] =
+static const char EX_RI_ED_BAD_SIG3[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55AfJo9FIePrxeDNnWT6SWkoz0/L27018XjUNWEHfaR06MAQAgBAAMgolK\n"
- "nLg3ZnVv0skzHCfmX+ZR9Ttwj7FNXfhXCsyr860S79OW5LD0/m1GcS9JflWhP+FO\n"
- "ng5cRb+aqNc8Ul+/4sQudZRx8w4U3d5rOuMGCqhQXnktH9AFzQHFq0jpAAU=\n"
+ "AQQABstQAVdvNBeuh/0X6D1QG7U4LBsMF66U4SuKDKplzNXLiKv7AQAgBADNUwKD\n"
+ "ETv10GLuZWuupZtT6HAGZNIhMHvYd1gGyBaoy86fsINj4Vxi9YctBHudNk2P8VIn\n"
+ "qFkmPvvSkJJaBgjVT638CvpTU3Bva4+8YTor4jpY3Ni6K9f9ALjg4U+UBQ8=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAPeK/znKLRvSUmCIUiZOgfhiRFt7XGN//C2GFuey4xkKiIr9LWMuVe9m\n"
- "Wx39Ea2UGEtNGCEVvZdJMDVRl7heFTfJTN4L1YeyWx6iNRWlpAmgQOKII7slHwlq\n"
- "seEULOLOXc9AsU/v9ba9G54DFbHfe2k44ZOwEmaQZW5VF/I0YMMdAgMBAAE=\n"
+ "MIGJAoGBANws+5gBYCgJhS4fYgStezRe+Y9mfuvTKWub9ytiZIiaPjtC4cu6+wuP\n"
+ "9bEQgiESx6GXL4L+CtcOSc8COFRPv1PxFXjkMKXfTAx57Rw8xc1qotWNshSUp7rL\n"
+ "JxSjOuEHd/dctIebor9akKPypAwnJhqrq+bqf9/kGaHckxK/ask/AgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 zVMCgxE79dBi7mVrrqWbU+hwBmTSITB72HdYBsgWqMs=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKFRzlrqPPxEW0nboAJ1qzKFb/vFtvRW0xNVb8RtbOY/NY5FV1hS8yfH\n"
- "igtugkrOBmWah7cmJhiON2j+TKeBxEoXwJMZeyV+HLbr7nY/mFhad4BQ3Frkl8d6\n"
- "1kQMhOJswMdwnnVHPNGUob4YAX0SpFA6MpBVj92zmMBeaihqUS9VAgMBAAE=\n"
+ "MIGJAoGBAMD0OLUYVhMiZz7tpxztxNwMTj4dQU9l++rRTfb+7vVZ+KAIb/8rjiU1\n"
+ "XXyV3AekijxQlOghj36lZBtethX8RyahsHmWyGqo1UmqCU1PtwfihdYuofvyI8Iu\n"
+ "V89G6QilsCPy2rpgYmEkmHt68FwlMnTjPUiKI5dZUk5WKrxsTgsxAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key br8svioLcJCAQxoo3KvlT288p8rb4lQIZNLlplkIKkw=\n"
- "ntor-onion-key-crosscert 0\n"
+ "ntor-onion-key DTa03lDz0APjbwCJN864xaYSxbPbVulLoAZIC4M4wGE=\n"
+ "ntor-onion-key-crosscert 1\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55AQyCiUqcuDdmdW/SyTMcJ+Zf5lH1O3CPsU1d+FcKzKvzAG9XqwmRm0uJ\n"
- "E49NoHcWr9IzdIwSGo+PJSkVpk95a5p2s065BetCWxEEBJQniajQf2hZ36zmV9rq\n"
- "a6puqkEAKAM=\n"
+ "AQoABstQAc1TAoMRO/XQYu5la66lm1PocAZk0iEwe9h3WAbIFqjLABej8E/aUX6f\n"
+ "2KFbmHFALYZCxszNCfg9HGQ+hfTjuTPONZ9yzudUoTTKq8MIMCD/5WKfzMJAHq/P\n"
+ "qNQuVt/gGA8=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "d6QGIVAJL5JjHUyV+aicLIdBYyxHwviKpPcp7uldRF8vfDGFpu0qFgJ5KT+3t36w\n"
- "QY1r75bvUMG/ZzGKDg95dcK0X2AK6GFlcrYyCoQEVOsuPc1QEUeK9P2s7viNQE4V\n"
- "tRwG/CvJhPfcnxErzVGfXIeYRL1r/hPNFDZSeSxPPM0=\n"
+ "syosw/6anYcwlNT5fGd1vCw9uFBUckIjGz3DmS1vVXzsTrdppcFotmzzYjV491xR\n"
+ "q8AyGyLlVIIuXabVuE+94ZpzDLWs82NqWMiYPNSNW2ctSVu+AE/KYjJCCz0SIE8/\n"
+ "bq40OQNQ6TNLWv1ubxZSDwcXrn4/VcV9IJrFjLpw2rA=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
- "router-sig-ed25519 ts9pFk8PnDWtXgQad09XC/ZCbruSx1U1pNOMWF9fyoNG0CodxdDH9Vglg+BOS7Nd9fmsINfPWKCVdVuSSM7zCA\n"
+ "proto Link=5\n"
"reject *:*\n"
+ "router-sig-ed25519 lemondcustard\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "YMl6mpQm7UCsPQhZKMm0aZ7fzGevWzRbQO+de20HTn7fVqMWQf2hBDJe9QTN/uDK\n"
- "/VKYT8SnIBexbrSMy1N5q8kNFKxxUtwA9GRtz620Vvc4m+lz/tnT9qucIKCDL5iJ\n"
- "eRpnls0JoAMIHKl99zdUioYubmOZuqUaRAdT8ulWy+Y=\n"
+ "d6F2sfCgQmo60QBPGGLZvMvwxw1h6DOlJO5NR31lgBrkLjnbaMJEtA8fNWOX5zW0\n"
+ "gXXrJlL0qlENGJUZeUFobxDOVzTA3dz92q97t/jqBu3pgjmyESesFFkAgqqAGjYh\n"
+ "RxUxJCDlyrmduGnl5GkjOVkS6UDhzRSRc+csxyXXp7E=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_RI_ED_BAD_CERT1[] =
+static const char EX_RI_ED_BAD_CROSSCERT1[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55AYf+rX8a5rzdTBGPvLdQIP8XcElDDQnJIruGqfDTj+tjAP+3XOL2UTmn\n"
- "Hu39PbLZV+m9DIj/DvG38M0hP4MmHUjP/iZG5PaCX6/aMe+nQSNuTl0IDGpIo1l8\n"
- "dZToQTFSzAQ=\n"
+ "AQQABstQAdQYl0NSJKxsHa9dGLZVBp+MohQmFDGSYOxdAmmrPS79AQAgBAD17lds\n"
+ "HKOpu0Y2u4RCynTWwgdA9YZWYgkB1GSeOzuy/8CaWrZvEg0iaZmsYIlgeujMxq/v\n"
+ "WEFzug6zYefoz93cN13o3pzAKY05A+KMvWPUnmvSlMqwlbnhjt3EjYoW9QQ=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAM4o2DrTwn3wrvUMm41S/hFL5ZtRHGRDh26o8htn14AKMC65vpygKFY7\n"
- "fUQVClAiJthAs5fD/8sE5XDtQrLnFv5OegQx8kSPuwyS/+5pI1bdxRJvKMOUl2Tc\n"
- "fAUhzeNBmPvW3lMi9Fksw5sCSAKQ5VH/+DlYvBGZIO49pTnOAty1AgMBAAE=\n"
+ "MIGJAoGBAMBQN6sno1t3m1izKZEoo63H5WrHfskJVor73sc7lDAo8BvQk110pIEd\n"
+ "2SGaFS9BNIUe51u4y8X+rDi3qXt5I11ifusvI1S6CMaM0p+Xh4osQGuvb31COpU7\n"
+ "MMOOxCVhmf2D/Vu1KuB+pNB91I7Id3BXRNdX7cuBCjdVEzdVZ9MTAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 9e5XbByjqbtGNruEQsp01sIHQPWGVmIJAdRknjs7sv8=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAMzIsJeEWWjN3Lp6qrzaJGn8uhJPJyjy2Wt3sp7z7iD/yBWW6Q7Jku3e\n"
- "C5QfKmSmNi2pNjS0SqPjqZZNsbcxpq/bEOcZdysZG1lqi/QgxUevk57RWjh3EFsG\n"
- "TwK3ougKWB5Q6/3m32dNsnnnDqzVapgZo7Zd3V/aCo0BVtL5VXZbAgMBAAE=\n"
+ "MIGJAoGBANK1iFyjGQGns3jmNpkO8t1f2RkWQTA9VS2xwbIZ0QE2QT3miu7ny3F5\n"
+ "992sLvs/XJGRh0Wr8I06MTXYqu1aZdqF+ailw/WTWwsqkWZwwRni8zWGW20zJ4Wv\n"
+ "2X5FmPQXQFVXb1pRmICIt94zQONE67xxfzG7pPs5IVl71WRFs6JnAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key W28nwT/5FJ818M78y/5sNOkxhQ7ENBhjVhGG2j6KvFY=\n"
- "ntor-onion-key-crosscert 0\n"
+ "ntor-onion-key ddfknkGy8CYAOi/IVWmQyBLb6hgY2KZSct8tCNRXzx0=\n"
+ "ntor-onion-key-crosscert 1\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55AYf+rX8a5rzdTBGPvLdQIP8XcElDDQnJIruGqfDTj+tjAP+3XOL2UTmn\n"
- "Hu39PbLZV+m9DIj/DvG38M0hP4MmHUjP/iZG5PaCX6/aMe+nQSNuTl0IDGpIo1l8\n"
- "dZToQTFSzAQ=\n"
+ "AQoABf55AXL4pAregsMa2ovmTBGaMCyWz/4LpICgAAuWXtTvA1IfAKo6ANUq+hi+\n"
+ "xb3J4aYafnszlj87oi/DR+SDf29wzwNw8gmaqGzJ5GbfISfABuTUCzlilZyVnLxi\n"
+ "BHcCH6PWiAQ=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "FWnEjvFob0ObgqohMT7miwGsAuioCT7Urz6tyWaGWph/TP9hbFWj4MPK5mt998mn\n"
- "xA8zHSF5n/edu7wVX+rtnPrYPBmg+qN8+Pq6XMg64CwtWu+sqigsi6vtz/TfAIDL\n"
- "mypENmSY32sWPvy/CA8dAZ2ASh57EH9a+WcFModpXkM=\n"
+ "zW3a26ATVWny3gEALe2VETRNIOFKMlRMCGjAKEyGQsGddSRYm08daaZkX7TzKRFq\n"
+ "TwZAcQ4BzhwCcnQtb/zwMSW1eIdKgO1rqZLhdo/awUuRtuPeG0vPoqahIQH3X81r\n"
+ "vh/Iy6f1xp3sfasib5AO8wZWhJ+LHaA1yt7DCfQBudU=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 88YqJdGJS4O6XiUCNrc9xbOHxujvcN/TkCoRuQQeKfZGHM+4IhI6AcXFlPIfDYq0SAavMhVmzsDDw0ROl7vyCQ\n"
+ "router-sig-ed25519 hKynmNoTSZn+Au4mlsO+yWIvCn9g2SpITDdbKDAgdLQ8qXJRG/oxiKOlmGuhpz7Q4ETSChkfOab4II3GNhQWBg\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "cU4WDO3w9ZfVRbNUgxOQMbwS2xWXvaL+cZmIV6AAjAZVWkLEpif4g6uYu+jJUZOS\n"
- "NUT7lNOMwTu4tE4b1YJpnD9T8iW0DlOXxlvRBMQYmKwhQuYk898BDGTSk+0AY0HJ\n"
- "vv8wRVewDajNhW7tFY907IdHvPXG0u83GANxkYrRyUg=\n"
+ "X37fMViJCh6+AQbMIWW9y8XwHridRmgcW5vZT93357C1NRy4MkuJt5O7sZ9YWE9g\n"
+ "8kKeeKRjXUfudbu00P/pmTKbLBucsPounK5uSpTs18FAed1p0wRDeM3KaddQsGjI\n"
+ "WuJe8hOufwyUWdFBBLJhH1rsCLJlY5P2lC6Wgs5WyEE=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_RI_ED_BAD_CERT2[] =
+static const char EX_RI_ED_MISPLACED1[] =
"router fred 127.0.0.1 9001 0 9002\n"
- "identity-ed25519\n"
- "-----BEGIN WOBBLY RUTABAGA-----\n"
- "helo\n"
- "-----END WOBBLY RUTABAGA-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANZvqyqFeiekh8ApqIGK4ZtOqjaX87EzDestvAWwamVOXiPoUrzXgM3O\n"
- "l8uuTnMA4TfnjLyyA2TnaMzJylOI1OMHuW/D9B/liWDstSxWNNIlKgLQ/Dh9xBS7\n"
- "uQb2PYlI+iMkPKPyJQSTDdGHE7cdFPewUfhRtJU3F5ztm/3FLBFvAgMBAAE=\n"
+ "MIGJAoGBAKh/VcmuyOszxrGZY8xIGAbQ7bXnSVf3iL+9RBKi3Lva0oN90zLYKfKt\n"
+ "Z0hBB/lHukUeaUZhTNx8ASTcoFnTcMD8rw1XQbjVyTdPWrHNVhZEGAD8TmeOrjEP\n"
+ "6/cLJTKxY2EAv/1Uli0F+mWInINRzdsa0EB9MbU9R1yr0YZMQZ8NAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABstQAWka/Nj7mht9fCo+vwXF59aGNWMDeuOhkcBq1m/WjG2vAQAgBABDDm8X\n"
+ "xgMoftELU7Umgf44257ImjgG1okFpkTGOq+K489uFUre+q+Ikurp+4H7j9d6kCIA\n"
+ "htYSDr1LfVBzxPttICRAX0cLg1rnIWRdB8TzXehF4/0hHAjtwkYKnPiVQQI=\n"
+ "-----END ED25519 CERT-----\n"
+ "master-key-ed25519 Qw5vF8YDKH7RC1O1JoH+ONueyJo4BtaJBaZExjqviuM=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANZl8U/Z8KCPS7EBDzt8i9kNETXS7vnp9gnw3BQNXfjiDtDg9eO7ChxY\n"
- "NBwuOTXmRxfX3W9kvZ0op9Hno6hixIhHzDql+vZ+hN7yPanVVDglSUXcr31yBm5K\n"
- "kA+ZnRvH3oVQ97E4rRzpi09dtI13Pzu7JS5jRMtH+JF1kQBoNC0dAgMBAAE=\n"
+ "MIGJAoGBAO9rHWfTdV5l8VtwNtwEDhd0BtmQpqxkXN0SV9pa6NLKeVMcROmlKL0u\n"
+ "EmF5njuLZTDRJk48HaT3/anU4qUGiDxtIU2np+eFkrYyLvyiaGyc20ph4ffLVzbG\n"
+ "VCSSkIVz4TYamplaBkY6yY+IBBk1u/klmeCBvgMhSIISxUklkxudAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key lUrEL+TVXpjjHQ2BIKk34vblyDmoyMro1a6/9hJ4VRc=\n"
- "ntor-onion-key-crosscert 0\n"
+ "ntor-onion-key PKfyrBmRFyANA+2PZAXawdNZom3VF+Cfg9lKy2OjuWM=\n"
+ "ntor-onion-key-crosscert 1\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55Abm5E7FBdd3F8N1xuz/vdv03zh2lABrmGjzPQ3AFJtntALNeQTgjv0JL\n"
- "jON4+SPNi0B2Bva3yKaSsdxiHQ1rIwQqIUVkzXmmX4jmsvJK/9gERAdD7GafTKZQ\n"
- "BaZbNXBvmQw=\n"
+ "AQoABstQAUMObxfGAyh+0QtTtSaB/jjbnsiaOAbWiQWmRMY6r4rjAJQykafOIJRQ\n"
+ "ex8+e+xpwVpyJJOidTVW2bBWG0ZIi+4W5Dj9eFiuV9x2kPTy7ZFueNAWZ7NstyTr\n"
+ "vLtNc5qRrg4=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "OxkqFsw1vHUQ9iPYcKC/MHUBtbLPK6JY2i81ccAai2eW118UXcTbeCRccrXyqSkl\n"
- "RLcooZyli1D6wg9x7O8+2+HXIbUa6WcTOD1Qi7Z9wKZfk4sDUy7QHKENMRfAXwX3\n"
- "U/gqd4BflMPp4+XrYfPzz+6yQPWp0t9wXbFv5hZ9F3k=\n"
+ "tqzgSiMy4U6J/yyYhg5hVIqO0vAgAwIMYPXWDRvAIomfnIpUCkHSIdyLD+7a4Yp3\n"
+ "ZhXbLug85b6bK3pOTB2cLI9v2gwsgOyewUdt8prZLTOPDF3EDRD7UKCNMrQIIBw6\n"
+ "kKwKIJVhAQKPi+gC2n7i07Y4zjGTaV4CiWe2h6E61lc=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 fW6Bt4R3xVk5KMDyOcYg8n5ANP0OrQq2PQFK2cW0lTAdi+eX+oT/BeWnkrn0uSWOC/t4omCmH4Rdl8M9xtpfBA\n"
+ "router-sig-ed25519 A1DMqknKoPrPRHr1Y1j8cd22Ziwcfl7b/3VKI4pthyLnFRpb768nlHi615YdwSve4L71d+c4vGMuKyeCcGbFDQ\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "DHxiQXuLxZR0ylqwUGGePgN4KF4ItlOV/DuGmmszCO/Ut0p+5s4FP2v6Mm9M92Wj\n"
- "75rS9xF/Ts0Kf49dvgc+c5VTvhX5I5SwGQkRk0RNJtNoP0t+qXBHaFV8BlAeaWF6\n"
- "Lg3O+GUK325fQv9uDPCe37mFQV9jafAzsZUrO/ggb1U=\n"
+ "KaOyGt84OBS8/83TQWKkfMLk/r/1ebWiA2Wkgda2cWx2L3Dh9V/3PDGwAWoG6m1r\n"
+ "20mVuLKwWCCNYG2fGC4J/NMETXI5p5b1+ze1KDYiO5hQtTJvMktmfa5+p0xLB43M\n"
+ "xjzpDoX0A37hP9XJa5d1Q7G2cnd64P70QqhToDtoswc=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_RI_ED_BAD_CERT3[] =
+static const char EX_RI_ED_MISPLACED2[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "BVVVnf55AW5TTGF9jCMl7aALZzqypD9Bj8WYnAPIrKCoIJdgMbY0AQAgBAB7eCn8\n"
- "rukx7t/egZUdqU7+FYqsnO4wdmOkLZkp0+gpF3jjk6N1Q0037NNVNZBjONB0Nm2F\n"
- "CpB3nWSJliSSKr5tOYsuBPFy5VVGYeKPakpOoxanQ1UcqevMBAQy0zf9hwA=\n"
+ "AQQABstQATjkYvZoN/RVHbJNtRWwmkazJVupqF/prNxdNJnRDWlDAQAgBADCNrLD\n"
+ "VQBs6tkIMGcR0PB+jrCvIuiQGGJzLsIfvxrG5UXWZsFEA5CnF6Lvjqu6p1CRkUF4\n"
+ "kpNC9xWcK8yDWhDCd5DLmFEDGFw/cD4rRACKatnQsGMN3KfDioWweSBI9wk=\n"
"-----END ED25519 CERT-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAPgeQNbKwpnTU+qW/2djh66hptS9rcy1B4vdyWkDTdREao2ECuCv691Y\n"
- "oIw3MpTWvpC1qHIKorunusR0FKgwXw3xQTikXbDq/1ptsekzoIA1R/hltQV3UuGH\n"
- "zdzHuQXAMX7Fdll2gyya03c3Yq5s+xSDvGdkEeaIoctKjwxp4SdNAgMBAAE=\n"
+ "MIGJAoGBAKdyNeuXJvnloOXD3iUxvvS7OBux3tpTfKxGdx124adeAKkiRL7EmXk3\n"
+ "LaUbHL3IhsVaf6JeyRzc+onEsD/uNeO0P7+GtvC5ZAkj1/6MxBaJioLGXoIacMak\n"
+ "NpmDYxhTcG75aEwgZX2RTla1j+5bIoG1o5Z76dkFMVUWsRtthFNRAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 wjayw1UAbOrZCDBnEdDwfo6wryLokBhicy7CH78axuU=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAOzWuH4cPW9rIrfi8MrruMUg4IUVHz4BxfY4/szMIUvzeEAdHn4FYkWy\n"
- "Vt7MDtUELZsmZeFNmkn72kLxnrdZ5XhxZBriq1Fzq11cSWRBF+SyE1MdcouY4GyG\n"
- "drw6T8xb8ty19q0eO6C/gw27iqXPAp1clvkroLg6Nv9lGZvsedVDAgMBAAE=\n"
+ "MIGJAoGBANBQwXgkKvrnfMDKDkV5x1bxlR07x+AOru5ypJH4qQh+GMYXpnkw0T7r\n"
+ "anIJtEFP0+FpbaRRI/xAPMpFUFsbeNH/+Yeove/6kKfv1rlgqWr/yI2XIW8Fl70i\n"
+ "DW2cnW43cwa/HDitFjE5vnkvkMWFn1XIgwhm7+NDIDbnmDkKZ8U7AgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key /vYZ+9yLqG7yUnutoI57s96JBl36GTz0IDWE244rbzE=\n"
+ "ntor-onion-key CbrcCjCeTGum8vZumB6lvTA00BztRN8tNn41GLHdkUI=\n"
"ntor-onion-key-crosscert 0\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55AZ4zVBWP/fIYEgWmyj0WpO6CkXRJjtrWXtiT02k3IddiAMpYgMemGIpN\n"
- "xj7TQRULsHHYvo4fLcKrSgndQbUUhfLTUuVhIzbnE2TBLMVOEkpxKU6mTuvTT/3h\n"
- "MJugrwTWVg4=\n"
+ "AQoABstQAcI2ssNVAGzq2QgwZxHQ8H6OsK8i6JAYYnMuwh+/GsblANS8qpQqkLmw\n"
+ "vcRttr/HvckIBY8i99OoqctPQziRUq2Up6Ag1b1MSgN3knRfi6wjmpz9Jn149kFx\n"
+ "HQ8sTCSu+QI=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "c/Vqu3wtsTsYMdnhTS9Tn1Pq6jDmH4uRD5WmbaCKKrkin2DjuYSMVpypndkdlZDE\n"
- "He7uF7SUO3QG/UcRIXYOsg9MSLUmvn2kIwef8ykyqlRh95Csjo5DyattUhL2w4QF\n"
- "tJkJBQAnXWaAVW1O8XimGCAvJ84cxbmZEcpN6WKjrXI=\n"
+ "DOH8ntVhHlms3NjkOvsCf5Qu1/DhHmJOL+J8ySD89lT2RBt0K07G9vAjc4NkkUpD\n"
+ "N2e9myNWbDCp8sjsYzWfqpv94IypSBEfwQFgV6peoAZxHkq35Nj9sIJ+rQloanJJ\n"
+ "RZkWyu1GILpggcNvWS6BYQQcRxu/lStLy917s24U7co=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "router-sig-ed25519 whWcVxkGo+l29Hsn+BLP96MReHTxQHTSgmMMzeQ4jZ0qV6B9kkj1Ma21oyl3iTmUCOtexgOiX5fImfMLkOxFDQ\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 Ue7bkPpOoc8ca7cyQj/Vq3BP5X4vwLA5QmpLGw/WfRNVRPojJRxU3RVqWMi3JbsJFRTe6pH6ZHyXER33G5aAAA\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "ifKUtbxmqHVs8A0oT5n7Te0c6D/XqWQTc0RxX9OKGspzh6wNX26h0Xa2vpK1Q9Zu\n"
- "sj61I7vbHuZN6rxiWs9IzJgb//XaNJasX1pd9tbGSXW+yYzc9G9kaa7vp3HcnhIP\n"
- "XVWzzS8WmOiVNGcF65j6f7yGloTgN7cHMptgJG7pWes=\n"
+ "py73sIYGI4awS9g4JFTSElHCg5pWYqEjLz/jbON7pZ80GGUG5wxXVxNRwtGvMrWk\n"
+ "zG2tW7SBm0TH6wdWeE5NhN1VSjgCqw7qSk2MJS2XHn5hBRTxzF4/Es/TJaziAqvY\n"
+ "e8ehZwqDPcG0vMhd97/uxoyKNdkyObhW+RNYRtGvCxg=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
-static const char EX_RI_BAD_EI_DIGEST2[] =
+static const char EX_RI_ED_BAD_CERT1[] =
"router fred 127.0.0.1 9001 0 9002\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf55ATrK8IVBWLO2yXKCqXLXJOTu89W2b+hREPO+tCrxjVqWAQAgBACG/vVx\n"
- "NK8wKVZvf34d75ZObSR0ge1N2RrAIKNslNXBq/tcllIrNE4S0ZNcMpA+hxXoVFeo\n"
- "jbxifYX7nTs5N3GrGPmkiuo82v2X6ZwoIXJGFnvWMxCjsYsUVDDxoT6h/w8=\n"
+ "AQoABf55AYf+rX8a5rzdTBGPvLdQIP8XcElDDQnJIruGqfDTj+tjAP+3XOL2UTmn\n"
+ "Hu39PbLZV+m9DIj/DvG38M0hP4MmHUjP/iZG5PaCX6/aMe+nQSNuTl0IDGpIo1l8\n"
+ "dZToQTFSzAQ=\n"
"-----END ED25519 CERT-----\n"
- "extra-info-digest E5FAC29E766D63F96AD175069640E803F2723765 99oo\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAK9wHSdRalxkuAybrSCA3dlEC1ZGc7oHOzXRGLg+z6batuiCdQtus1Rk\n"
- "LP821eZJtEMAE56aewCIHDcTiCxVa6DMqmxRjm5pfW4G5H5QCPYT6Fu0RoYck3Ef\n"
- "vkgits5/fNYGPPVC7k8AdGax5dKj5oFVGq+JWolYFRv6tyR9AThvAgMBAAE=\n"
+ "MIGJAoGBALkr+jsRorIXiOA6obO6OLPitE/d+OzWz1SH6CHRs0m5KL+T6M9t0qqK\n"
+ "O2BTOmrjPTaGdEsakkcfiZeSj02MviuSadZ/JF8FoAYx9yCbmlAh/FE3qvoY1lrE\n"
+ "mAZhA2sTc32sHusQNBKRFfGHeckaE0i9MW7L+Crq2dLcwI/YZEldAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "master-key-ed25519 brKx2WhJlN4ExqUOr6CTx20MX57JkAetrrTwpt1cEt8=\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAKxjxTQ/T/MHpFbk7/zwA7l5b3IW3yVcyVe6eIGFoYun8FI0fbYRmR4M\n"
- "G5Asu07gP9Bbgt3AFPuEqrjg4u+lIkgqTcCgKWJbAgm7fslwaDTXQ36A7I1M95PD\n"
- "GJ10Dk5v4dVbrqwoF7MSrQPFtMO91RP11nGPSvDqXZJ4XpwqwdxpAgMBAAE=\n"
+ "MIGJAoGBAM8kNdNCiheKwYmN+wA+/aCLtr1aRJtoYggQPGT3rhm8m2bOhxixjdCD\n"
+ "jiDkqfYjnaNizNnwpS47h1MWHzgTWKF/QS4JXvCG5M56KDJot2z03qbdoRUv5+Z9\n"
+ "yQIx6ad1p2Km24P4IHmAYItwFBGir7y86C6mOdX4Sp139hDJOIsZAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key LuVmHxpj4F5mPXGNi4MtxbIbLMav6frJRBsRgAvpdzo=\n"
- "ntor-onion-key-crosscert 0\n"
+ "ntor-onion-key AP9U8b/4WUiOB899TlNgoYrnUdUqrwQYLgF0Smsj8E0=\n"
+ "ntor-onion-key-crosscert 1\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf55AYb+9XE0rzApVm9/fh3vlk5tJHSB7U3ZGsAgo2yU1cGrAKBcSzwi4lY/\n"
- "salCELOLdeZzOjDNnBd6cKp2WJg7Yz5zFlbVbyNk0iwfGmucHk8vQZe5BS0Oq/Pz\n"
- "B1u/BcJv8gk=\n"
+ "AQoABstQAW6ysdloSZTeBMalDq+gk8dtDF+eyZAHra608KbdXBLfAKPMVgkcGgA4\n"
+ "8B+Bu8/lk14zBtzryJKvwg8UVOVd0tPnX7GiVyPmDCPbEZPnHG3Yvq+ir6HkiZAO\n"
+ "mirgIIhkPwI=\n"
"-----END ED25519 CERT-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "QsAQVdDVHtasDbhrZG4ZxImdTTMY7fz3vouAiGyZx6/jCCB5v0gHwTn4xo6pgLEW\n"
- "LQfMhQZIr76Ky67c0hAN2hihuDlfvhfVe9c2c5UOH1BOhq3llE3Hc3xGyEy3rw7r\n"
- "5y38YGi759CvsP2/L8JfXMuBg89OcgJYFa27Q6e6MdQ=\n"
+ "GnUJtlnkqHZKQAzwNPgAesR1R7hebqY/hMIKj9s/y+PxGgs+aNP2gfv4W+dtQ209\n"
+ "jHGxF+n6s2hm3Am0EFQ2h1ULTJh9uYnIs1f1kyx8DdydXdx3pZcURLRenmiRowB7\n"
+ "iGn76ICqqGVZKpGtszmSe3L35XXl7HwzJTjYzcs95vo=\n"
"-----END CROSSCERT-----\n"
"published 2014-10-05 12:00:00\n"
"bandwidth 1000 1000 1000\n"
+ "proto Link=5\n"
"reject *:*\n"
- "router-sig-ed25519 5zoQ0dufeeOJ/tE/BgcWgM8JpfW1ELSXLz4dI+K8YRH/gUtaPmYJgU2QfeUHD0oy1iwv4Qvl8Ferga7aBk1+DA\n"
+ "router-sig-ed25519 RqA4oirneie/ywl6j99vc2B1mUlMfIlakR7M6M4Minf7x6t7EMOsNVvOMKBSsPaBu/qcoOwhMynHdhTCmWHpBw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "D6KRMwkb6JmVEnpZ825SD3LMB84UmVy0i94xk44OwhoWNKLXhaSTWJgf6AqnPG5o\n"
- "QrCypSb44bYLn+VaDN5LVUl36jeZqCT4xd+4ZwIRdPOUj7vcVmyUDg3lXcAIk97Q\n"
- "E5PrQY1mQuLSIjjKInAR2NRBumNJtRw31Y/DTB7tODU=\n"
+ "Ui31suskhBbwTRc24NfUneh1c2LfUqjap5dCCfdmoVgvTSnk2RDW+IC4jwwFliWp\n"
+ "Gs2RJsPy527LRPRrXKJv3MnKO6uUPZXUjs/QZjdJgTMCzLY7jJBwnmAqj5BjUMfO\n"
+ "+S3hOhBZlDmLeYk4p+sppZjR0P9EFy2e3U3homiz1dM=\n"
"-----END SIGNATURE-----\n"
- "\n"
;
diff --git a/src/test/failing_routerdescs.template b/src/test/failing_routerdescs.template
new file mode 100644
index 0000000000..cc2bae3a40
--- /dev/null
+++ b/src/test/failing_routerdescs.template
@@ -0,0 +1,812 @@
+:::comment=this file is to be used with the makedescs.py utility
+:::name=MINIMAL
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+
+:::name=MAXIMAL
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject 127.0.0.1:*
+accept *:80
+reject *:*
+ipv6-policy accept 80,100,101
+uptime 1000
+hibernating 0
+unrecognized-keywords are just dandy in this format
+platform Tor 0.2.4.23 on a Banana PC Jr 6000 Series
+contact O.W.Jones
+fingerprint {d.RSA_FINGERPRINT}
+read-history 900 1,2,3,4
+write-history 900 1,2,3,4
+extra-info-digest AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+hidden-service-dir
+allow-single-hop-exits
+family $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA $BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
+caches-extra-info
+or-address [::1:2:3:4]:9999
+or-address 127.0.0.99:10000
+opt fred is a fine router
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+
+:::comment=this one has somebody else's signature.
+:::name=BAD_SIG1
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+-----BEGIN SIGNATURE-----
+aV5gqy5fTtsrdntTPRPGdeN376lXK+blHJuqbAL0WQ7XaMB4r+F8/whFu0cObOqD
+AqAhxkcMu721iYCkUNQvhc3FDou2i1mBJFDrhZEtux/2aXODIMG+OPdDUCyBqeQR
+oYLLfLR4ZZic1tlBFRRNdtXGF2SHeIM052F7PbeJz2A=
+-----END SIGNATURE-----
+
+
+:::name=bad_tokens
+:::type=ri
+router bob
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_published
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 99:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_bandwidth
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth why hello there
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=bad_onionkey
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+-----BEGIN RSA PUBLIC KEY-----
+MIGHAoGBANBKlyoqApWzG7UzmXcxhXM4T370FbN1edPbw4WAczBDXJslXCU9Xk1r
+fKfoi/+WiTGvH7RcZWPm7wnThq2u2EAO/IPPcLE9cshLBkK28EvDg5K/WsYedbY9
+1Gou+7ZSwMEPv2b13c7eWnSW1YvFa64pVDKu2sKnIjX6Bm0HZGbXAgED=
+-----END RSA PUBLIC KEY-----
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_ports
+:::type=ri
+router fred 127.0.0.1 900001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=neg_bandwidth
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 -1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=bad_ip
+:::type=ri
+router fred 100.127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_dirport
+:::type=ri
+router fred 127.0.0.1 9001 0 bob
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_name2
+:::type=ri
+router verylongnamethatnevereverendsandgoesontoolong 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_bandwidth2
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 hello 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=bad_uptime
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+uptime forever-and-a-day
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_bandwidth3
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 -1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_ntor_key
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key x{d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_fingerprint
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+fingerprint 5555
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=mismatched_fingerprint
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+fingerprint CC43 DC8E 8C9E 3E6D 59CD 0399 2491 0C8C E1E4 50D2
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_has_accept6
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+accept6 *:80
+reject6 *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_no_exit_policy
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_ipv6_exit_policy
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+ipv6-policy kfdslfdfj sdjfk sdfjsdf
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=bad_family
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+family aaaa,bbbb
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=zero_orport
+:::type=ri
+router fred 127.0.0.1 0 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=ed_missing_crosscert
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=ed_missing_crosscert2
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=ed_missing_crosscert_sign
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+:::name=ed_bad_sig1
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dg
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=ed_bad_sig2
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 X{d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=ed_bad_sig3
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 lemondcustard
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=ed_bad_crosscert1
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert 1
+-----BEGIN ED25519 CERT-----
+AQoABf55AXL4pAregsMa2ovmTBGaMCyWz/4LpICgAAuWXtTvA1IfAKo6ANUq+hi+
+xb3J4aYafnszlj87oi/DR+SDf29wzwNw8gmaqGzJ5GbfISfABuTUCzlilZyVnLxi
+BHcCH6PWiAQ=
+-----END ED25519 CERT-----
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=ed_misplaced1
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+signing-key
+{d.RSA_IDENTITY}
+identity-ed25519
+{d.ED_CERT}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=ed_misplaced2
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+router-sig-ed25519 {d.ED_SIGNATURE}
+proto Link=5
+reject *:*
+router-signature
+{d.RSA_SIGNATURE}
+
+
+:::name=ed_bad_cert1
+:::type=ri
+router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+-----BEGIN ED25519 CERT-----
+AQoABf55AYf+rX8a5rzdTBGPvLdQIP8XcElDDQnJIruGqfDTj+tjAP+3XOL2UTmn
+Hu39PbLZV+m9DIj/DvG38M0hP4MmHUjP/iZG5PaCX6/aMe+nQSNuTl0IDGpIo1l8
+dZToQTFSzAQ=
+-----END ED25519 CERT-----
+signing-key
+{d.RSA_IDENTITY}
+master-key-ed25519 {d.ED_IDENTITY}
+onion-key
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+proto Link=5
+reject *:*
+router-sig-ed25519 {d.ED_SIGNATURE}
+router-signature
+{d.RSA_SIGNATURE}
diff --git a/src/test/fakechans.h b/src/test/fakechans.h
index 4006e1bec4..c3accb1637 100644
--- a/src/test/fakechans.h
+++ b/src/test/fakechans.h
@@ -1,4 +1,4 @@
- /* Copyright (c) 2014-2019, The Tor Project, Inc. */
+ /* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_FAKECHANS_H
diff --git a/src/test/fakecircs.c b/src/test/fakecircs.c
new file mode 100644
index 0000000000..4d5b97197e
--- /dev/null
+++ b/src/test/fakecircs.c
@@ -0,0 +1,91 @@
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file fakecircs.c
+ * \brief Fake circuits API for unit test.
+ **/
+
+#define CIRCUITBUILD_PRIVATE
+#define CIRCUITLIST_PRIVATE
+#define CRYPT_PATH_PRIVATE
+
+#include "core/or/or.h"
+
+#include "core/crypto/relay_crypto.h"
+#include "core/or/channel.h"
+#include "core/or/circuitbuild.h"
+#include "core/or/circuitlist.h"
+#include "core/or/circuitpadding.h"
+#include "core/or/crypt_path.h"
+#include "core/or/relay.h"
+#include "core/or/relay_crypto_st.h"
+
+#include "test/fakecircs.h"
+
+/** Return newly allocated OR circuit using the given nchan and pchan. It must
+ * be freed with the free_fake_orcirc(). */
+or_circuit_t *
+new_fake_orcirc(channel_t *nchan, channel_t *pchan)
+{
+ or_circuit_t *orcirc = NULL;
+ circuit_t *circ = NULL;
+ crypt_path_t tmp_cpath;
+ char whatevs_key[CPATH_KEY_MATERIAL_LEN];
+
+ orcirc = tor_malloc_zero(sizeof(*orcirc));
+ circ = &(orcirc->base_);
+ circ->magic = OR_CIRCUIT_MAGIC;
+
+ circuit_set_n_circid_chan(circ, get_unique_circ_id_by_chan(nchan), nchan);
+ cell_queue_init(&(circ->n_chan_cells));
+
+ circ->n_hop = NULL;
+ circ->streams_blocked_on_n_chan = 0;
+ circ->streams_blocked_on_p_chan = 0;
+ circ->n_delete_pending = 0;
+ circ->p_delete_pending = 0;
+ circ->received_destroy = 0;
+ circ->state = CIRCUIT_STATE_OPEN;
+ circ->purpose = CIRCUIT_PURPOSE_OR;
+ circ->package_window = CIRCWINDOW_START_MAX;
+ circ->deliver_window = CIRCWINDOW_START_MAX;
+ circ->n_chan_create_cell = NULL;
+
+ circuit_set_p_circid_chan(orcirc, get_unique_circ_id_by_chan(pchan), pchan);
+ cell_queue_init(&(orcirc->p_chan_cells));
+
+ memset(&tmp_cpath, 0, sizeof(tmp_cpath));
+ if (cpath_init_circuit_crypto(&tmp_cpath, whatevs_key,
+ sizeof(whatevs_key), 0, 0)<0) {
+ log_warn(LD_BUG,"Circuit initialization failed");
+ return NULL;
+ }
+ orcirc->crypto = tmp_cpath.pvt_crypto;
+
+ return orcirc;
+}
+
+/** Free fake OR circuit which MUST be created by new_fake_orcirc(). */
+void
+free_fake_orcirc(or_circuit_t *orcirc)
+{
+ if (!orcirc) {
+ return;
+ }
+
+ circuit_t *circ = TO_CIRCUIT(orcirc);
+
+ relay_crypto_clear(&orcirc->crypto);
+
+ circpad_circuit_free_all_machineinfos(circ);
+
+ if (orcirc->p_chan && orcirc->p_chan->cmux) {
+ circuitmux_detach_circuit(orcirc->p_chan->cmux, circ);
+ }
+ if (circ->n_chan && circ->n_chan->cmux) {
+ circuitmux_detach_circuit(circ->n_chan->cmux, circ);
+ }
+
+ tor_free_(circ);
+}
diff --git a/src/test/fakecircs.h b/src/test/fakecircs.h
new file mode 100644
index 0000000000..ed8a150a3f
--- /dev/null
+++ b/src/test/fakecircs.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file fakecircs.h
+ * \brief Declarations for fake circuits for test suite use.
+ **/
+
+#ifndef TOR_FAKECIRCS_H
+#define TOR_FAKECIRCS_H
+
+#include "core/or/or_circuit_st.h"
+
+or_circuit_t *new_fake_orcirc(channel_t *nchan, channel_t *pchan);
+void free_fake_orcirc(or_circuit_t *orcirc);
+
+#endif /* !defined(TOR_FAKECIRCS_H) */
diff --git a/src/test/fuzz/.may_include b/src/test/fuzz/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/test/fuzz/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/test/fuzz/fixup_filenames.sh b/src/test/fuzz/fixup_filenames.sh
index 68efc1abc5..f730d532a5 100755
--- a/src/test/fuzz/fixup_filenames.sh
+++ b/src/test/fuzz/fixup_filenames.sh
@@ -8,9 +8,9 @@ if [ ! -d "$1" ] ; then
fi
for fn in "$1"/* ; do
- prev=`basename "$fn"`
- post=`sha256sum "$fn" | sed -e 's/ .*//;'`
- if [ "$prev" == "$post" ] ; then
+ prev=$(basename "$fn")
+ post=$(sha256sum "$fn" | sed -e 's/ .*//;')
+ if [ "$prev" = "$post" ] ; then
echo "OK $prev"
else
echo "mv $prev $post"
diff --git a/src/test/fuzz/fuzz_consensus.c b/src/test/fuzz/fuzz_consensus.c
index 5947a3f48c..f2bf29ea78 100644
--- a/src/test/fuzz/fuzz_consensus.c
+++ b/src/test/fuzz/fuzz_consensus.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define SIGCOMMON_PRIVATE
#include "core/or/or.h"
@@ -61,13 +61,13 @@ int
fuzz_main(const uint8_t *data, size_t sz)
{
networkstatus_t *ns;
- char *str = tor_memdup_nulterm(data, sz);
const char *eos = NULL;
networkstatus_type_t tp = NS_TYPE_CONSENSUS;
if (tor_memstr(data, MIN(sz, 1024), "tus vote"))
tp = NS_TYPE_VOTE;
const char *what = (tp == NS_TYPE_CONSENSUS) ? "consensus" : "vote";
- ns = networkstatus_parse_vote_from_string(str,
+ ns = networkstatus_parse_vote_from_string((const char *)data,
+ sz,
&eos,
tp);
if (ns) {
@@ -76,6 +76,6 @@ fuzz_main(const uint8_t *data, size_t sz)
} else {
log_debug(LD_GENERAL, "Parsing as %s failed", what);
}
- tor_free(str);
+
return 0;
}
diff --git a/src/test/fuzz/fuzz_descriptor.c b/src/test/fuzz/fuzz_descriptor.c
index 58ee3dbc35..eb4d4d507f 100644
--- a/src/test/fuzz/fuzz_descriptor.c
+++ b/src/test/fuzz/fuzz_descriptor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define SIGCOMMON_PRIVATE
#include "core/or/or.h"
diff --git a/src/test/fuzz/fuzz_diff.c b/src/test/fuzz/fuzz_diff.c
index 1bc60e50ee..9cd2116245 100644
--- a/src/test/fuzz/fuzz_diff.c
+++ b/src/test/fuzz/fuzz_diff.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONSDIFF_PRIVATE
@@ -10,9 +10,11 @@
#include "test/fuzz/fuzzing.h"
static int
-mock_consensus_compute_digest_(const char *c, consensus_digest_t *d)
+mock_consensus_compute_digest_(const char *c, size_t len,
+ consensus_digest_t *d)
{
(void)c;
+ (void)len;
memset(d->sha3_256, 3, sizeof(d->sha3_256));
return 0;
}
@@ -42,28 +44,34 @@ fuzz_main(const uint8_t *stdin_buf, size_t data_size)
if (! separator)
return 0;
size_t c1_len = separator - stdin_buf;
- char *c1 = tor_memdup_nulterm(stdin_buf, c1_len);
+ const char *c1 = (const char *)stdin_buf;
size_t c2_len = data_size - c1_len - SEPLEN;
- char *c2 = tor_memdup_nulterm(separator + SEPLEN, c2_len);
+ const char *c2 = (const char *)separator + SEPLEN;
- char *c3 = consensus_diff_generate(c1, c2);
+ const char *cp = memchr(c1, 0, c1_len);
+ if (cp)
+ c1_len = cp - c1;
+
+ cp = memchr(c2, 0, c2_len);
+ if (cp)
+ c2_len = cp - c2;
+
+ char *c3 = consensus_diff_generate(c1, c1_len, c2, c2_len);
if (c3) {
- char *c4 = consensus_diff_apply(c1, c3);
+ char *c4 = consensus_diff_apply(c1, c1_len, c3, strlen(c3));
tor_assert(c4);
- if (strcmp(c2, c4)) {
- printf("%s\n", escaped(c1));
- printf("%s\n", escaped(c2));
+ int equal = (c2_len == strlen(c4)) && fast_memeq(c2, c4, c2_len);
+ if (! equal) {
+ //printf("%s\n", escaped(c1));
+ //printf("%s\n", escaped(c2));
printf("%s\n", escaped(c3));
printf("%s\n", escaped(c4));
}
- tor_assert(! strcmp(c2, c4));
+ tor_assert(equal);
tor_free(c3);
tor_free(c4);
}
- tor_free(c1);
- tor_free(c2);
return 0;
}
-
diff --git a/src/test/fuzz/fuzz_diff_apply.c b/src/test/fuzz/fuzz_diff_apply.c
index 9bd3cb0bf8..a819c73338 100644
--- a/src/test/fuzz/fuzz_diff_apply.c
+++ b/src/test/fuzz/fuzz_diff_apply.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONSDIFF_PRIVATE
@@ -10,9 +10,11 @@
#include "test/fuzz/fuzzing.h"
static int
-mock_consensus_compute_digest_(const char *c, consensus_digest_t *d)
+mock_consensus_compute_digest_(const char *c, size_t len,
+ consensus_digest_t *d)
{
(void)c;
+ (void)len;
memset(d->sha3_256, 3, sizeof(d->sha3_256));
return 0;
}
@@ -50,16 +52,13 @@ fuzz_main(const uint8_t *stdin_buf, size_t data_size)
if (! separator)
return 0;
size_t c1_len = separator - stdin_buf;
- char *c1 = tor_memdup_nulterm(stdin_buf, c1_len);
+ const char *c1 = (const char *)stdin_buf;
size_t c2_len = data_size - c1_len - SEPLEN;
- char *c2 = tor_memdup_nulterm(separator + SEPLEN, c2_len);
+ const char *c2 = (const char *)separator + SEPLEN;
- char *c3 = consensus_diff_apply(c1, c2);
+ char *c3 = consensus_diff_apply(c1, c1_len, c2, c2_len);
- tor_free(c1);
- tor_free(c2);
tor_free(c3);
return 0;
}
-
diff --git a/src/test/fuzz/fuzz_extrainfo.c b/src/test/fuzz/fuzz_extrainfo.c
index f18bd68d65..ad21254e3e 100644
--- a/src/test/fuzz/fuzz_extrainfo.c
+++ b/src/test/fuzz/fuzz_extrainfo.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define SIGCOMMON_PRIVATE
#include "core/or/or.h"
diff --git a/src/test/fuzz/fuzz_hsdescv2.c b/src/test/fuzz/fuzz_hsdescv2.c
index 34639b237c..81d9e5f00e 100644
--- a/src/test/fuzz/fuzz_hsdescv2.c
+++ b/src/test/fuzz/fuzz_hsdescv2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
#include "feature/dirparse/unparseable.h"
diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c
index 2cbd655898..8d7eab1a8d 100644
--- a/src/test/fuzz/fuzz_hsdescv3.c
+++ b/src/test/fuzz/fuzz_hsdescv3.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define HS_DESCRIPTOR_PRIVATE
@@ -35,16 +35,21 @@ mock_rsa_ed25519_crosscert_check(const uint8_t *crosscert,
static size_t
mock_decrypt_desc_layer(const hs_descriptor_t *desc,
- const uint8_t *encrypted_blob,
- size_t encrypted_blob_size,
const uint8_t *descriptor_cookie,
- int is_superencrypted_layer,
+ bool is_superencrypted_layer,
char **decrypted_out)
{
(void)is_superencrypted_layer;
(void)desc;
(void)descriptor_cookie;
const size_t overhead = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN;
+ const uint8_t *encrypted_blob = (is_superencrypted_layer)
+ ? desc->plaintext_data.superencrypted_blob
+ : desc->superencrypted_data.encrypted_blob;
+ size_t encrypted_blob_size = (is_superencrypted_layer)
+ ? desc->plaintext_data.superencrypted_blob_size
+ : desc->superencrypted_data.encrypted_blob_size;
+
if (encrypted_blob_size < overhead)
return 0;
*decrypted_out = tor_memdup_nulterm(
@@ -80,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);
@@ -96,4 +101,3 @@ fuzz_main(const uint8_t *data, size_t sz)
tor_free(fuzzing_data);
return 0;
}
-
diff --git a/src/test/fuzz/fuzz_http.c b/src/test/fuzz/fuzz_http.c
index 2798c47d23..a4fd182f1e 100644
--- a/src/test/fuzz/fuzz_http.c
+++ b/src/test/fuzz/fuzz_http.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -8,7 +8,7 @@
#include "core/or/or.h"
#include "lib/err/backtrace.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "feature/dircache/dircache.h"
diff --git a/src/test/fuzz/fuzz_http_connect.c b/src/test/fuzz/fuzz_http_connect.c
index a60fc36804..9e5a48ba4d 100644
--- a/src/test/fuzz/fuzz_http_connect.c
+++ b/src/test/fuzz/fuzz_http_connect.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -8,7 +8,7 @@
#include "core/or/or.h"
#include "lib/err/backtrace.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
diff --git a/src/test/fuzz/fuzz_iptsv2.c b/src/test/fuzz/fuzz_iptsv2.c
index 76fa3c164e..bc51ffcdb8 100644
--- a/src/test/fuzz/fuzz_iptsv2.c
+++ b/src/test/fuzz/fuzz_iptsv2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/fuzz/fuzz_microdesc.c b/src/test/fuzz/fuzz_microdesc.c
index 28fdc5e24d..3fc709183b 100644
--- a/src/test/fuzz/fuzz_microdesc.c
+++ b/src/test/fuzz/fuzz_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/fuzz/fuzz_multi.sh b/src/test/fuzz/fuzz_multi.sh
index b4a17ed8cb..406ab498d9 100755
--- a/src/test/fuzz/fuzz_multi.sh
+++ b/src/test/fuzz/fuzz_multi.sh
@@ -1,3 +1,5 @@
+#!/bin/sh
+
MEMLIMIT_BYTES=21990500990976
N_CPUS=1
@@ -6,9 +8,9 @@ if [ $# -ge 1 ]; then
shift
fi
-FILTER=echo
+FILTER="echo"
-for i in `seq -w "$N_CPUS"`; do
+for i in $(seq -w "$N_CPUS"); do
if [ "$i" -eq 1 ]; then
if [ "$N_CPUS" -eq 1 ]; then
INSTANCE=""
diff --git a/src/test/fuzz/fuzz_socks.c b/src/test/fuzz/fuzz_socks.c
index 06cb08391e..4e7cb4d48d 100644
--- a/src/test/fuzz/fuzz_socks.c
+++ b/src/test/fuzz/fuzz_socks.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -6,7 +6,7 @@
#define BUFFERS_PRIVATE
#include "core/or/or.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "lib/err/backtrace.h"
#include "lib/log/log.h"
#include "core/proto/proto_socks.h"
diff --git a/src/test/fuzz/fuzz_strops.c b/src/test/fuzz/fuzz_strops.c
new file mode 100644
index 0000000000..05d9101e72
--- /dev/null
+++ b/src/test/fuzz/fuzz_strops.c
@@ -0,0 +1,253 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file fuzz_strops.c
+ * \brief Fuzzers for various string encoding/decoding operations
+ **/
+
+#include "orconfig.h"
+
+#include "lib/cc/torint.h"
+#include "lib/ctime/di_ops.h"
+#include "lib/encoding/binascii.h"
+#include "lib/encoding/cstring.h"
+#include "lib/encoding/kvline.h"
+#include "lib/encoding/confline.h"
+#include "lib/malloc/malloc.h"
+#include "lib/log/escape.h"
+#include "lib/log/util_bug.h"
+#include "lib/intmath/muldiv.h"
+
+#include "test/fuzz/fuzzing.h"
+
+#include <stdio.h>
+#include <string.h>
+
+int
+fuzz_init(void)
+{
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+typedef struct chunk_t {
+ uint8_t *buf;
+ size_t len;
+} chunk_t;
+
+#define chunk_free(ch) \
+ FREE_AND_NULL(chunk_t, chunk_free_, (ch))
+
+static chunk_t *
+chunk_new(size_t len)
+{
+ chunk_t *ch = tor_malloc(sizeof(chunk_t));
+ ch->buf = tor_malloc(len);
+ ch->len = len;
+ return ch;
+}
+static void
+chunk_free_(chunk_t *ch)
+{
+ if (!ch)
+ return;
+ tor_free(ch->buf);
+ tor_free(ch);
+}
+static bool
+chunk_eq(const chunk_t *a, const chunk_t *b)
+{
+ return a->len == b->len && fast_memeq(a->buf, b->buf, a->len);
+}
+
+static chunk_t *
+b16_dec(const chunk_t *inp)
+{
+ chunk_t *ch = chunk_new(CEIL_DIV(inp->len, 2));
+ int r = base16_decode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len);
+ if (r >= 0) {
+ ch->len = r;
+ } else {
+ chunk_free(ch);
+ }
+ return ch;
+}
+static chunk_t *
+b16_enc(const chunk_t *inp)
+{
+ chunk_t *ch = chunk_new(inp->len * 2 + 1);
+ base16_encode((char *)ch->buf, ch->len, (char*)inp->buf, inp->len);
+ return ch;
+}
+
+static chunk_t *
+b32_dec(const chunk_t *inp)
+{
+ chunk_t *ch = chunk_new(inp->len);//XXXX
+ int r = base32_decode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len);
+ if (r >= 0) {
+ ch->len = r;
+ } else {
+ chunk_free(ch);
+ }
+ return ch;
+}
+static chunk_t *
+b32_enc(const chunk_t *inp)
+{
+ chunk_t *ch = chunk_new(base32_encoded_size(inp->len));
+ base32_encode((char *)ch->buf, ch->len, (char*)inp->buf, inp->len);
+ ch->len = strlen((char *) ch->buf);
+ return ch;
+}
+
+static chunk_t *
+b64_dec(const chunk_t *inp)
+{
+ chunk_t *ch = chunk_new(inp->len);//XXXX This could be shorter.
+ int r = base64_decode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len);
+ if (r >= 0) {
+ ch->len = r;
+ } else {
+ chunk_free(ch);
+ }
+ return ch;
+}
+static chunk_t *
+b64_enc(const chunk_t *inp)
+{
+ chunk_t *ch = chunk_new(BASE64_BUFSIZE(inp->len));
+ base64_encode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len, 0);
+ ch->len = strlen((char *) ch->buf);
+ return ch;
+}
+
+static chunk_t *
+c_dec(const chunk_t *inp)
+{
+ char *s = tor_memdup_nulterm(inp->buf, inp->len);
+ chunk_t *ch = tor_malloc(sizeof(chunk_t));
+ char *r = NULL;
+ (void) unescape_string(s, &r, &ch->len);
+ tor_free(s);
+ ch->buf = (uint8_t*) r;
+ if (!ch->buf) {
+ tor_free(ch);
+ }
+ return ch;
+}
+static chunk_t *
+c_enc(const chunk_t *inp)
+{
+ char *s = tor_memdup_nulterm(inp->buf, inp->len);
+ chunk_t *ch = tor_malloc(sizeof(chunk_t));
+ ch->buf = (uint8_t*)esc_for_log(s);
+ tor_free(s);
+ ch->len = strlen((char*)ch->buf);
+ return ch;
+}
+
+static int kv_flags = 0;
+static config_line_t *
+kv_dec(const chunk_t *inp)
+{
+ char *s = tor_memdup_nulterm(inp->buf, inp->len);
+ config_line_t *res = kvline_parse(s, kv_flags);
+ tor_free(s);
+ return res;
+}
+static chunk_t *
+kv_enc(const config_line_t *inp)
+{
+ char *s = kvline_encode(inp, kv_flags);
+ if (!s)
+ return NULL;
+ chunk_t *res = tor_malloc(sizeof(chunk_t));
+ res->buf = (uint8_t*)s;
+ res->len = strlen(s);
+ return res;
+}
+
+/* Given an encoder function, a decoder function, and a function to free
+ * the decoded object, check whether any string that successfully decoded
+ * will then survive an encode-decode-encode round-trip unchanged.
+ */
+#define ENCODE_ROUNDTRIP(E,D,FREE) \
+ STMT_BEGIN { \
+ bool err = false; \
+ a = D(&inp); \
+ if (!a) \
+ return 0; \
+ b = E(a); \
+ tor_assert(b); \
+ c = D(b); \
+ tor_assert(c); \
+ d = E(c); \
+ tor_assert(d); \
+ if (!chunk_eq(b,d)) { \
+ printf("Unequal chunks: %s\n", \
+ hex_str((char*)b->buf, b->len)); \
+ printf(" vs %s\n", \
+ hex_str((char*)d->buf, d->len)); \
+ err = true; \
+ } \
+ FREE(a); \
+ chunk_free(b); \
+ FREE(c); \
+ chunk_free(d); \
+ tor_assert(!err); \
+ } STMT_END
+
+int
+fuzz_main(const uint8_t *stdin_buf, size_t data_size)
+{
+ if (!data_size)
+ return 0;
+
+ chunk_t inp = { (uint8_t*)stdin_buf, data_size };
+ chunk_t *b=NULL,*d=NULL;
+ void *a=NULL,*c=NULL;
+
+ switch (stdin_buf[0]) {
+ case 0:
+ ENCODE_ROUNDTRIP(b16_enc, b16_dec, chunk_free_);
+ break;
+ case 1:
+ ENCODE_ROUNDTRIP(b32_enc, b32_dec, chunk_free_);
+ break;
+ case 2:
+ ENCODE_ROUNDTRIP(b64_enc, b64_dec, chunk_free_);
+ break;
+ case 3:
+ ENCODE_ROUNDTRIP(c_enc, c_dec, chunk_free_);
+ break;
+ case 5:
+ kv_flags = KV_QUOTED|KV_OMIT_KEYS;
+ ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
+ break;
+ case 6:
+ kv_flags = 0;
+ ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
+ break;
+ case 7:
+ kv_flags = KV_OMIT_VALS;
+ ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
+ break;
+ case 8:
+ kv_flags = KV_QUOTED;
+ ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
+ break;
+ case 9:
+ kv_flags = KV_QUOTED|KV_OMIT_VALS;
+ ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
+ break;
+ }
+
+ return 0;
+}
diff --git a/src/test/fuzz/fuzz_vrs.c b/src/test/fuzz/fuzz_vrs.c
index 967397d1af..d6e88e59e7 100644
--- a/src/test/fuzz/fuzz_vrs.c
+++ b/src/test/fuzz/fuzz_vrs.c
@@ -1,8 +1,9 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define NS_PARSE_PRIVATE
#define NETWORKSTATUS_PRIVATE
#include "core/or/or.h"
+#include "feature/dirauth/dirvote.h"
#include "feature/dirparse/ns_parse.h"
#include "feature/dirparse/unparseable.h"
#include "lib/memarea/memarea.h"
@@ -35,9 +36,12 @@ fuzz_init(void)
dummy_vote = tor_malloc_zero(sizeof(*dummy_vote));
dummy_vote->known_flags = smartlist_new();
smartlist_split_string(dummy_vote->known_flags,
- "Authority BadExit Exit Fast Guard HSDir "
- "NoEdConsensus Running Stable V2Dir Valid",
+ DIRVOTE_UNIVERSAL_FLAGS,
" ", 0, 0);
+ smartlist_split_string(dummy_vote->known_flags,
+ DIRVOTE_OPTIONAL_FLAGS,
+ " ", 0, 0);
+ smartlist_sort_strings(dummy_vote->known_flags);
return 0;
}
@@ -53,24 +57,24 @@ fuzz_cleanup(void)
int
fuzz_main(const uint8_t *data, size_t sz)
{
- char *str = tor_memdup_nulterm(data, sz);
const char *s;
routerstatus_t *rs_ns = NULL, *rs_md = NULL, *rs_vote = NULL;
vote_routerstatus_t *vrs = tor_malloc_zero(sizeof(*vrs));
smartlist_t *tokens = smartlist_new();
+ const char *eos = (const char *)data + sz;
- s = str;
- rs_ns = routerstatus_parse_entry_from_string(area, &s, tokens,
+ s = (const char *)data;
+ rs_ns = routerstatus_parse_entry_from_string(area, &s, eos, tokens,
NULL, NULL, 26, FLAV_NS);
tor_assert(smartlist_len(tokens) == 0);
- s = str;
- rs_md = routerstatus_parse_entry_from_string(area, &s, tokens,
+ s = (const char *)data;
+ rs_md = routerstatus_parse_entry_from_string(area, &s, eos, tokens,
NULL, NULL, 26, FLAV_MICRODESC);
tor_assert(smartlist_len(tokens) == 0);
- s = str;
- rs_vote = routerstatus_parse_entry_from_string(area, &s, tokens,
+ s = (const char *)data;
+ rs_vote = routerstatus_parse_entry_from_string(area, &s, eos, tokens,
dummy_vote, vrs, 26, FLAV_NS);
tor_assert(smartlist_len(tokens) == 0);
@@ -82,6 +86,6 @@ fuzz_main(const uint8_t *data, size_t sz)
vote_routerstatus_free(vrs);
memarea_clear(area);
smartlist_free(tokens);
- tor_free(str);
+
return 0;
}
diff --git a/src/test/fuzz/fuzzing.h b/src/test/fuzz/fuzzing.h
index 150ac4aa7d..6cbcdc41ad 100644
--- a/src/test/fuzz/fuzzing.h
+++ b/src/test/fuzz/fuzzing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef FUZZING_H
#define FUZZING_H
@@ -9,5 +9,5 @@ int fuzz_main(const uint8_t *data, size_t sz);
void disable_signature_checking(void);
-#endif /* FUZZING_H */
+#endif /* !defined(FUZZING_H) */
diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c
index 8ea4898522..d9719074ad 100644
--- a/src/test/fuzz/fuzzing_common.c
+++ b/src/test/fuzz/fuzzing_common.c
@@ -1,14 +1,17 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CRYPTO_ED25519_PRIVATE
+#define CONFIG_PRIVATE
#include "orconfig.h"
#include "core/or/or.h"
+#include "app/main/subsysmgr.h"
#include "lib/err/backtrace.h"
#include "app/config/config.h"
#include "test/fuzz/fuzzing.h"
#include "lib/compress/compress.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_init.h"
+#include "lib/version/torversion.h"
static or_options_t *mock_options = NULL;
static const or_options_t *
@@ -94,12 +97,10 @@ disable_signature_checking(void)
static void
global_init(void)
{
- tor_threads_init();
- tor_compress_init();
+ subsystems_init_upto(SUBSYS_LEVEL_LIBS);
+ flush_log_messages_from_startup();
- /* Initialise logging first */
- init_logging(1);
- configure_backtrace_handler(get_version());
+ tor_compress_init();
if (crypto_global_init(0, NULL, NULL) < 0)
abort();
@@ -111,7 +112,7 @@ global_init(void)
}
/* set up the options. */
- mock_options = tor_malloc_zero(sizeof(or_options_t));
+ mock_options = options_new();
MOCK(get_options, mock_get_options);
/* Make BUG() and nonfatal asserts crash */
@@ -137,7 +138,7 @@ LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
return fuzz_main(Data, Size);
}
-#else /* Not LLVM_FUZZ, so AFL. */
+#else /* !defined(LLVM_FUZZ) */
int
main(int argc, char **argv)
@@ -166,7 +167,7 @@ main(int argc, char **argv)
memset(&s, 0, sizeof(s));
set_log_severity_config(loglevel, LOG_ERR, &s);
/* ALWAYS log bug warnings. */
- s.masks[LOG_WARN-LOG_ERR] |= LD_BUG;
+ s.masks[SEVERITY_MASK_IDX(LOG_WARN)] |= LD_BUG;
add_stream_log(&s, "", fileno(stdout));
}
@@ -189,9 +190,9 @@ main(int argc, char **argv)
if (fuzz_cleanup() < 0)
abort();
- tor_free(mock_options);
+ or_options_free(mock_options);
UNMOCK(get_options);
return 0;
}
-#endif
+#endif /* defined(LLVM_FUZZ) */
diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am
index 27eeced8c5..ef952c3812 100644
--- a/src/test/fuzz/include.am
+++ b/src/test/fuzz/include.am
@@ -7,17 +7,18 @@ FUZZING_CFLAGS = \
FUZZING_LDFLAG = \
@TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) @TOR_LDFLAGS_libevent@
FUZZING_LIBS = \
- $(TOR_INTERNAL_TESTING_LIBS) \
+ src/test/libtor-testing.a \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ \
- @TOR_ZSTD_LIBS@
+ @TOR_ZSTD_LIBS@ \
+ @TOR_TRACE_LIBS@
oss-fuzz-prereqs: \
- $(TOR_INTERNAL_TESTING_LIBS)
+ src/test/libtor-testing.a
noinst_HEADERS += \
src/test/fuzz/fuzzing.h
@@ -153,6 +154,16 @@ src_test_fuzz_fuzz_socks_LDADD = $(FUZZING_LIBS)
endif
if UNITTESTS_ENABLED
+src_test_fuzz_fuzz_strops_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_strops.c
+src_test_fuzz_fuzz_strops_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_strops_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_strops_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_strops_LDADD = $(FUZZING_LIBS)
+endif
+
+if UNITTESTS_ENABLED
src_test_fuzz_fuzz_vrs_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_vrs.c
@@ -176,6 +187,7 @@ FUZZERS = \
src/test/fuzz/fuzz-iptsv2 \
src/test/fuzz/fuzz-microdesc \
src/test/fuzz/fuzz-socks \
+ src/test/fuzz/fuzz-strops \
src/test/fuzz/fuzz-vrs
endif
@@ -291,6 +303,15 @@ src_test_fuzz_lf_fuzz_socks_LDADD = $(LIBFUZZER_LIBS)
endif
if UNITTESTS_ENABLED
+src_test_fuzz_lf_fuzz_strops_SOURCES = \
+ $(src_test_fuzz_fuzz_strops_SOURCES)
+src_test_fuzz_lf_fuzz_strops_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_strops_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_strops_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_strops_LDADD = $(LIBFUZZER_LIBS)
+endif
+
+if UNITTESTS_ENABLED
src_test_fuzz_lf_fuzz_vrs_SOURCES = \
$(src_test_fuzz_fuzz_vrs_SOURCES)
src_test_fuzz_lf_fuzz_vrs_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
@@ -312,6 +333,7 @@ LIBFUZZER_FUZZERS = \
src/test/fuzz/lf-fuzz-iptsv2 \
src/test/fuzz/lf-fuzz-microdesc \
src/test/fuzz/lf-fuzz-socks \
+ src/test/fuzz/lf-fuzz-strops \
src/test/fuzz/lf-fuzz-vrs
else
@@ -406,6 +428,13 @@ src_test_fuzz_liboss_fuzz_socks_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
endif
if UNITTESTS_ENABLED
+src_test_fuzz_liboss_fuzz_strops_a_SOURCES = \
+ $(src_test_fuzz_fuzz_strops_SOURCES)
+src_test_fuzz_liboss_fuzz_strops_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_strops_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+endif
+
+if UNITTESTS_ENABLED
src_test_fuzz_liboss_fuzz_vrs_a_SOURCES = \
$(src_test_fuzz_fuzz_vrs_SOURCES)
src_test_fuzz_liboss_fuzz_vrs_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
@@ -425,6 +454,7 @@ OSS_FUZZ_FUZZERS = \
src/test/fuzz/liboss-fuzz-iptsv2.a \
src/test/fuzz/liboss-fuzz-microdesc.a \
src/test/fuzz/liboss-fuzz-socks.a \
+ src/test/fuzz/liboss-fuzz-strops.a \
src/test/fuzz/liboss-fuzz-vrs.a
else
diff --git a/src/test/fuzz/minimize.sh b/src/test/fuzz/minimize.sh
index 87d3dda13c..ce43812bb8 100755
--- a/src/test/fuzz/minimize.sh
+++ b/src/test/fuzz/minimize.sh
@@ -7,7 +7,7 @@ if [ ! -d "$1" ] ; then
exit 1
fi
-which=`basename "$1"`
+which=$(basename "$1")
mkdir "$1.out"
afl-cmin -i "$1" -o "$1.out" -m none "./src/test/fuzz/fuzz-${which}"
diff --git a/src/test/fuzz_static_testcases.sh b/src/test/fuzz_static_testcases.sh
index f7b3adffb1..b883352402 100755
--- a/src/test/fuzz_static_testcases.sh
+++ b/src/test/fuzz_static_testcases.sh
@@ -14,7 +14,7 @@ fi
for fuzzer in "${builddir:-.}"/src/test/fuzz/fuzz-* ; do
- f=`basename $fuzzer`
+ f=$(basename "$fuzzer")
case="${f#fuzz-}"
if [ -d "${TOR_FUZZ_CORPORA}/${case}" ]; then
echo "Running tests for ${case}"
diff --git a/src/test/hs_build_address.py b/src/test/hs_build_address.py
index 7ff22c3a9a..91864eabcb 100644
--- a/src/test/hs_build_address.py
+++ b/src/test/hs_build_address.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/hs_indexes.py b/src/test/hs_indexes.py
index af0b81f8de..5c6d893a66 100644
--- a/src/test/hs_indexes.py
+++ b/src/test/hs_indexes.py
@@ -7,6 +7,11 @@
# store/fetch the descriptor on the hashring. (hs_build_hs_index()).
#
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/hs_ntor_ref.py b/src/test/hs_ntor_ref.py
index d58ac3ca23..98025dd584 100644
--- a/src/test/hs_ntor_ref.py
+++ b/src/test/hs_ntor_ref.py
@@ -41,6 +41,11 @@ The whole logic and concept for this test suite was taken from ntor_ref.py.
*** DO NOT USE THIS IN PRODUCTION. ***
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import struct
import os, sys
import binascii
diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c
index f2ae8398df..e9aafa4760 100644
--- a/src/test/hs_test_helpers.c
+++ b/src/test/hs_test_helpers.c
@@ -1,17 +1,34 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#define HS_CLIENT_PRIVATE
+
#include "core/or/or.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "test/test.h"
#include "feature/nodelist/torcert.h"
+#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
+#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;
@@ -21,31 +38,45 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
/* For a usable intro point we need at least two link specifiers: One legacy
* keyid and one ipv4 */
{
- hs_desc_link_specifier_t *ls_legacy = tor_malloc_zero(sizeof(*ls_legacy));
- hs_desc_link_specifier_t *ls_v4 = tor_malloc_zero(sizeof(*ls_v4));
- ls_legacy->type = LS_LEGACY_ID;
- memcpy(ls_legacy->u.legacy_id, "0299F268FCA9D55CD157976D39AE92B4B455B3A8",
- DIGEST_LEN);
- ls_v4->u.ap.port = 9001;
- int family = tor_addr_parse(&ls_v4->u.ap.addr, addr);
+ tor_addr_t a;
+ tor_addr_make_unspec(&a);
+ link_specifier_t *ls_legacy = link_specifier_new();
+ link_specifier_t *ls_ip = link_specifier_new();
+ link_specifier_set_ls_type(ls_legacy, LS_LEGACY_ID);
+ memset(link_specifier_getarray_un_legacy_id(ls_legacy), 'C',
+ link_specifier_getlen_un_legacy_id(ls_legacy));
+ int family = tor_addr_parse(&a, addr);
switch (family) {
case AF_INET:
- ls_v4->type = LS_IPV4;
+ link_specifier_set_ls_type(ls_ip, LS_IPV4);
+ link_specifier_set_un_ipv4_addr(ls_ip, tor_addr_to_ipv4h(&a));
+ link_specifier_set_un_ipv4_port(ls_ip, 9001);
break;
case AF_INET6:
- ls_v4->type = LS_IPV6;
+ link_specifier_set_ls_type(ls_ip, LS_IPV6);
+ memcpy(link_specifier_getarray_un_ipv6_addr(ls_ip),
+ tor_addr_to_in6_addr8(&a),
+ link_specifier_getlen_un_ipv6_addr(ls_ip));
+ link_specifier_set_un_ipv6_port(ls_ip, 9001);
break;
default:
- /* Stop the test, not suppose to have an error. */
- tt_int_op(family, OP_EQ, AF_INET);
+ /* Stop the test, not supposed to have an error.
+ * Compare with -1 to show the actual family.
+ */
+ tt_int_op(family, OP_EQ, -1);
}
smartlist_add(ip->link_specifiers, ls_legacy);
- smartlist_add(ip->link_specifiers, ls_v4);
+ smartlist_add(ip->link_specifiers, ls_ip);
}
- ret = ed25519_keypair_generate(&auth_kp, 0);
- tt_int_op(ret, ==, 0);
- ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY,
+ 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_ed25519(signing_kp,
+ CERT_TYPE_AUTH_HS_IP_KEY,
&auth_kp.pubkey, now,
HS_DESC_CERT_LIFETIME,
CERT_FLAG_INCLUDE_SIGNING_KEY);
@@ -55,7 +86,7 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
ip->legacy.key = crypto_pk_new();
tt_assert(ip->legacy.key);
ret = crypto_pk_generate_key(ip->legacy.key);
- tt_int_op(ret, ==, 0);
+ tt_int_op(ret, OP_EQ, 0);
ssize_t cert_len = tor_make_rsa_ed25519_crosscert(
&signing_kp->pubkey, ip->legacy.key,
now + HS_DESC_CERT_LIFETIME,
@@ -72,16 +103,23 @@ 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, ==, 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,
+ cross_cert = tor_cert_create_ed25519(signing_kp,
+ CERT_TYPE_CROSS_HS_IP_KEYS,
&ed25519_kp.pubkey, time(NULL),
HS_DESC_CERT_LIFETIME,
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;
@@ -119,7 +157,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
sizeof(ed25519_public_key_t));
desc->plaintext_data.signing_key_cert =
- tor_cert_create(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC,
+ tor_cert_create_ed25519(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC,
&signing_kp->pubkey, now, 3600,
CERT_FLAG_INCLUDE_SIGNING_KEY);
tt_assert(desc->plaintext_data.signing_key_cert);
@@ -127,11 +165,11 @@ 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);
- tt_int_op(ret, ==, 0);
+ tt_int_op(ret, OP_EQ, 0);
memcpy(&desc->superencrypted_data.auth_ephemeral_pubkey,
&auth_ephemeral_kp.pubkey,
sizeof(curve25519_public_key_t));
@@ -152,13 +190,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;
@@ -173,7 +215,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());
@@ -198,11 +240,39 @@ hs_helper_build_hs_desc_no_ip(const ed25519_keypair_t *signing_kp)
return hs_helper_build_hs_desc_impl(1, signing_kp);
}
+hs_descriptor_t *
+hs_helper_build_hs_desc_with_client_auth(
+ const uint8_t *descriptor_cookie,
+ const curve25519_public_key_t *client_pk,
+ const ed25519_keypair_t *signing_kp)
+{
+ curve25519_keypair_t auth_ephemeral_kp;
+ hs_descriptor_t *desc = hs_helper_build_hs_desc_impl(0, signing_kp);
+ hs_desc_authorized_client_t *desc_client;
+
+ /* The number of client authorized auth has tobe a multiple of
+ * HS_DESC_AUTH_CLIENT_MULTIPLE so remove one that we'll replace. */
+ desc_client = smartlist_get(desc->superencrypted_data.clients, 0);
+ smartlist_remove(desc->superencrypted_data.clients, desc_client);
+ hs_desc_authorized_client_free(desc_client);
+
+ desc_client = tor_malloc_zero(sizeof(hs_desc_authorized_client_t));
+
+ curve25519_keypair_generate(&auth_ephemeral_kp, 0);
+ 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,
+ &auth_ephemeral_kp.seckey,
+ descriptor_cookie, desc_client);
+ smartlist_add(desc->superencrypted_data.clients, desc_client);
+ return desc;
+}
+
void
hs_helper_desc_equal(const hs_descriptor_t *desc1,
const hs_descriptor_t *desc2)
{
- char *addr1 = NULL, *addr2 = NULL;
/* Plaintext data section. */
tt_int_op(desc1->plaintext_data.version, OP_EQ,
desc2->plaintext_data.version);
@@ -216,7 +286,7 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
tt_mem_op(desc1->plaintext_data.blinded_pubkey.pubkey, OP_EQ,
desc2->plaintext_data.blinded_pubkey.pubkey,
ED25519_PUBKEY_LEN);
- tt_u64_op(desc1->plaintext_data.revision_counter, ==,
+ tt_u64_op(desc1->plaintext_data.revision_counter, OP_EQ,
desc2->plaintext_data.revision_counter);
/* NOTE: We can't compare the encrypted blob because when encoding the
@@ -233,7 +303,7 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
{
tt_assert(desc1->superencrypted_data.clients);
tt_assert(desc2->superencrypted_data.clients);
- tt_int_op(smartlist_len(desc1->superencrypted_data.clients), ==,
+ tt_int_op(smartlist_len(desc1->superencrypted_data.clients), OP_EQ,
smartlist_len(desc2->superencrypted_data.clients));
for (int i=0;
i < smartlist_len(desc1->superencrypted_data.clients);
@@ -251,15 +321,15 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
}
/* Encrypted data section. */
- tt_uint_op(desc1->encrypted_data.create2_ntor, ==,
+ tt_uint_op(desc1->encrypted_data.create2_ntor, OP_EQ,
desc2->encrypted_data.create2_ntor);
/* Authentication type. */
- tt_int_op(!!desc1->encrypted_data.intro_auth_types, ==,
+ tt_int_op(!!desc1->encrypted_data.intro_auth_types, OP_EQ,
!!desc2->encrypted_data.intro_auth_types);
if (desc1->encrypted_data.intro_auth_types &&
desc2->encrypted_data.intro_auth_types) {
- tt_int_op(smartlist_len(desc1->encrypted_data.intro_auth_types), ==,
+ tt_int_op(smartlist_len(desc1->encrypted_data.intro_auth_types), OP_EQ,
smartlist_len(desc2->encrypted_data.intro_auth_types));
for (int i = 0;
i < smartlist_len(desc1->encrypted_data.intro_auth_types);
@@ -273,7 +343,7 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
{
tt_assert(desc1->encrypted_data.intro_points);
tt_assert(desc2->encrypted_data.intro_points);
- tt_int_op(smartlist_len(desc1->encrypted_data.intro_points), ==,
+ tt_int_op(smartlist_len(desc1->encrypted_data.intro_points), OP_EQ,
smartlist_len(desc2->encrypted_data.intro_points));
for (int i=0; i < smartlist_len(desc1->encrypted_data.intro_points); i++) {
hs_desc_intro_point_t *ip1 = smartlist_get(desc1->encrypted_data
@@ -288,38 +358,76 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1,
tt_mem_op(&ip1->enc_key, OP_EQ, &ip2->enc_key, CURVE25519_PUBKEY_LEN);
}
- tt_int_op(smartlist_len(ip1->link_specifiers), ==,
+ tt_int_op(smartlist_len(ip1->link_specifiers), OP_EQ,
smartlist_len(ip2->link_specifiers));
for (int j = 0; j < smartlist_len(ip1->link_specifiers); j++) {
- hs_desc_link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j),
- *ls2 = smartlist_get(ip2->link_specifiers, j);
- tt_int_op(ls1->type, ==, ls2->type);
- switch (ls1->type) {
+ link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j),
+ *ls2 = smartlist_get(ip2->link_specifiers, j);
+ tt_int_op(link_specifier_get_ls_type(ls1), OP_EQ,
+ link_specifier_get_ls_type(ls2));
+ switch (link_specifier_get_ls_type(ls1)) {
case LS_IPV4:
+ {
+ uint32_t addr1 = link_specifier_get_un_ipv4_addr(ls1);
+ uint32_t addr2 = link_specifier_get_un_ipv4_addr(ls2);
+ tt_int_op(addr1, OP_EQ, addr2);
+ uint16_t port1 = link_specifier_get_un_ipv4_port(ls1);
+ uint16_t port2 = link_specifier_get_un_ipv4_port(ls2);
+ tt_int_op(port1, OP_EQ, port2);
+ }
+ break;
case LS_IPV6:
{
- addr1 = tor_addr_to_str_dup(&ls1->u.ap.addr);
- addr2 = tor_addr_to_str_dup(&ls2->u.ap.addr);
- tt_str_op(addr1, OP_EQ, addr2);
- tor_free(addr1);
- tor_free(addr2);
- tt_int_op(ls1->u.ap.port, ==, ls2->u.ap.port);
+ const uint8_t *addr1 =
+ link_specifier_getconstarray_un_ipv6_addr(ls1);
+ const uint8_t *addr2 =
+ link_specifier_getconstarray_un_ipv6_addr(ls2);
+ tt_int_op(link_specifier_getlen_un_ipv6_addr(ls1), OP_EQ,
+ link_specifier_getlen_un_ipv6_addr(ls2));
+ tt_mem_op(addr1, OP_EQ, addr2,
+ link_specifier_getlen_un_ipv6_addr(ls1));
+ uint16_t port1 = link_specifier_get_un_ipv6_port(ls1);
+ uint16_t port2 = link_specifier_get_un_ipv6_port(ls2);
+ tt_int_op(port1, OP_EQ, port2);
}
break;
case LS_LEGACY_ID:
- tt_mem_op(ls1->u.legacy_id, OP_EQ, ls2->u.legacy_id,
- sizeof(ls1->u.legacy_id));
+ {
+ const uint8_t *id1 =
+ link_specifier_getconstarray_un_legacy_id(ls1);
+ const uint8_t *id2 =
+ link_specifier_getconstarray_un_legacy_id(ls2);
+ tt_int_op(link_specifier_getlen_un_legacy_id(ls1), OP_EQ,
+ link_specifier_getlen_un_legacy_id(ls2));
+ tt_mem_op(id1, OP_EQ, id2,
+ link_specifier_getlen_un_legacy_id(ls1));
+ }
break;
default:
/* Unknown type, caught it and print its value. */
- tt_int_op(ls1->type, OP_EQ, -1);
+ tt_int_op(link_specifier_get_ls_type(ls1), OP_EQ, -1);
}
}
}
}
done:
- tor_free(addr1);
- tor_free(addr2);
+ ;
}
+void
+hs_helper_add_client_auth(const ed25519_public_key_t *service_pk,
+ const curve25519_secret_key_t *client_sk)
+{
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ if (client_auths == NULL) {
+ client_auths = digest256map_new();
+ set_hs_client_auths_map(client_auths);
+ }
+
+ hs_client_service_authorization_t *auth =
+ tor_malloc_zero(sizeof(hs_client_service_authorization_t));
+ memcpy(&auth->enc_seckey, client_sk, sizeof(curve25519_secret_key_t));
+ hs_build_address(service_pk, HS_VERSION_THREE, auth->onion_address);
+ digest256map_set(client_auths, service_pk->pubkey, auth);
+}
diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h
index 9662a83ba8..23d11f2a4a 100644
--- a/src/test/hs_test_helpers.h
+++ b/src/test/hs_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_HS_TEST_HELPERS_H
@@ -8,18 +8,26 @@
#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(
const ed25519_keypair_t *signing_kp);
+hs_descriptor_t *hs_helper_build_hs_desc_with_client_auth(
+ const uint8_t *descriptor_cookie,
+ const curve25519_public_key_t *client_pk,
+ 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);
-#endif /* !defined(TOR_HS_TEST_HELPERS_H) */
+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 c13c5f2c2d..ba802e7b04 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -24,6 +24,8 @@ TESTSCRIPTS = \
src/test/test_workqueue_pipe2.sh \
src/test/test_workqueue_socketpair.sh \
src/test/test_switch_id.sh \
+ src/test/test_cmdline.sh \
+ src/test/test_parseconf.sh \
src/test/unittest_part1.sh \
src/test/unittest_part2.sh \
src/test/unittest_part3.sh \
@@ -39,8 +41,26 @@ TESTSCRIPTS += \
endif
if USEPYTHON
-TESTSCRIPTS += src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh
+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/run_check_subsystem_order.sh
+
+if COVERAGE_ENABLED
+# ...
+else
+# Only do this when coverage is not on, since it invokes lots of code
+# in a kind of unpredictable way.
TESTSCRIPTS += src/test/test_rebind.sh
+TESTSCRIPTS += src/test/test_include.sh
+endif
+endif
+
+if USE_PERL
+TESTSCRIPTS += \
+ scripts/maint/checkSpaceTest.sh
endif
TESTS += src/test/test-slow src/test/test-memwipe \
@@ -51,13 +71,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-v3-min single-onion-v3
+
+# run a quick test or two
+# this test only uses IPv4
+TEST_CHUTNEY_FLAVOR_QUICK = bridges+hs-v3
# only run if we can ping6 ::1 (localhost)
-# IPv6-only v3 single onion services don't work yet.
-TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v3-ipv6
+TEST_CHUTNEY_FLAVOR_QUICK_IPV6 = single-onion-v3-ipv6-md
+
+# run a basic set of tests, which only use IPv4
+TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v3-min single-onion-v3
+
+# only run if we can ping ::1 (localhost)
+TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v3-ipv6 single-onion-v3-ipv6-md
+
# only run if we can find a stable (or simply another) version of tor
TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v3
+# only run if IPv6 and mixed networks are run
+TEST_CHUTNEY_FLAVORS_IPV6_MIXED = mixed+hs-v3-ipv6
+
### This is a lovely feature, but it requires automake >= 1.12, and Tor
### doesn't require that yet.
###
@@ -70,10 +102,11 @@ noinst_PROGRAMS+= \
src/test/test \
src/test/test-slow \
src/test/test-memwipe \
- src/test/test-child \
+ src/test/test-process \
src/test/test_workqueue \
src/test/test-switch-id \
- src/test/test-timers
+ src/test/test-timers \
+ src/test/test-rng
endif
src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
@@ -89,31 +122,42 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
src_test_test_SOURCES =
if UNITTESTS_ENABLED
+
+# ADD_C_FILE: INSERT SOURCES HERE.
src_test_test_SOURCES += \
+ src/test/fakecircs.c \
src/test/log_test_helpers.c \
src/test/hs_test_helpers.c \
+ src/test/opts_test_helpers.c \
src/test/rend_test_helpers.c \
+ src/test/resolve_test_helpers.c \
+ src/test/rng_test_helpers.c \
src/test/test.c \
src/test/test_accounting.c \
src/test/test_addr.c \
src/test/test_address.c \
src/test/test_address_set.c \
src/test/test_bridges.c \
+ src/test/test_btrack.c \
src/test/test_buffers.c \
src/test/test_bwmgt.c \
src/test/test_cell_formats.c \
src/test/test_cell_queue.c \
src/test/test_channel.c \
src/test/test_channelpadding.c \
+ src/test/test_circuitpadding.c \
src/test/test_channeltls.c \
src/test/test_checkdir.c \
src/test/test_circuitlist.c \
src/test/test_circuitmux.c \
+ src/test/test_circuitmux_ewma.c \
src/test/test_circuitbuild.c \
src/test/test_circuituse.c \
src/test/test_circuitstats.c \
src/test/test_compat_libevent.c \
src/test/test_config.c \
+ src/test/test_confmgr.c \
+ src/test/test_confparse.c \
src/test/test_connection.c \
src/test/test_conscache.c \
src/test/test_consdiff.c \
@@ -123,10 +167,13 @@ src_test_test_SOURCES += \
src/test/test_controller_events.c \
src/test/test_crypto.c \
src/test/test_crypto_ope.c \
+ src/test/test_crypto_rng.c \
src/test/test_data.c \
src/test/test_dir.c \
+ src/test/test_dirvote.c \
src/test/test_dir_common.c \
src/test/test_dir_handle_get.c \
+ src/test/test_dispatch.c \
src/test/test_dos.c \
src/test/test_entryconn.c \
src/test/test_entrynodes.c \
@@ -142,27 +189,40 @@ 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 \
+ src/test/test_hs_dos.c \
+ src/test/test_hs_metrics.c \
src/test/test_introduce.c \
src/test/test_keypin.c \
src/test/test_link_handshake.c \
src/test/test_logging.c \
src/test/test_mainloop.c \
+ src/test/test_metrics.c \
src/test/test_microdesc.c \
+ src/test/test_namemap.c \
+ src/test/test_netinfo.c \
src/test/test_nodelist.c \
src/test/test_oom.c \
src/test/test_oos.c \
src/test/test_options.c \
+ src/test/test_options_act.c \
src/test/test_pem.c \
src/test/test_periodic_event.c \
src/test/test_policy.c \
+ src/test/test_process.c \
+ src/test/test_process_descs.c \
+ src/test/test_prob_distr.c \
src/test/test_procmon.c \
+ src/test/test_proto_haproxy.c \
src/test/test_proto_http.c \
src/test/test_proto_misc.c \
src/test/test_protover.c \
src/test/test_pt.c \
+ src/test/test_pubsub_build.c \
+ src/test/test_pubsub_msg.c \
src/test/test_relay.c \
src/test/test_relaycell.c \
src/test/test_relaycrypt.c \
@@ -173,19 +233,25 @@ src_test_test_SOURCES += \
src/test/test_routerlist.c \
src/test/test_routerset.c \
src/test/test_scheduler.c \
+ src/test/test_sendme.c \
src/test/test_shared_random.c \
src/test/test_socks.c \
+ src/test/test_statefile.c \
+ src/test/test_stats.c \
src/test/test_status.c \
src/test/test_storagedir.c \
src/test/test_threads.c \
+ src/test/test_token_bucket.c \
src/test/test_tortls.c \
src/test/test_util.c \
src/test/test_util_format.c \
src/test/test_util_process.c \
+ src/test/test_voting_flags.c \
src/test/test_voting_schedule.c \
src/test/test_x509.c \
src/test/test_helpers.c \
src/test/test_dns.c \
+ src/test/test_parsecommon.c \
src/test/testing_common.c \
src/test/testing_rsakeys.c \
src/ext/tinytest.c
@@ -203,9 +269,13 @@ endif
src_test_test_slow_SOURCES =
if UNITTESTS_ENABLED
src_test_test_slow_SOURCES += \
+ src/test/rng_test_helpers.c \
src/test/test_slow.c \
src/test/test_crypto_slow.c \
- src/test/test_util_slow.c \
+ src/test/test_process_slow.c \
+ src/test/test_prob_distr.c \
+ src/test/ptr_helpers.c \
+ src/test/test_ptr_slow.c \
src/test/testing_common.c \
src/test/testing_rsakeys.c \
src/ext/tinytest.c
@@ -238,24 +308,29 @@ src_test_test_switch_id_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
-
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_USERENV@ \
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
src_test_test_LDADD = \
- $(TOR_INTERNAL_TESTING_LIBS) \
+ src/test/libtor-testing.a \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_slow_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_slow_CFLAGS = $(src_test_test_CFLAGS)
src_test_test_slow_LDADD = $(src_test_test_LDADD)
src_test_test_slow_LDFLAGS = $(src_test_test_LDFLAGS)
+src_test_test_rng_CPPFLAGS = $(src_test_test_CPPFLAGS)
+src_test_test_rng_CFLAGS = $(src_test_test_CFLAGS)
+src_test_test_rng_SOURCES = src/test/test_rng.c
+src_test_test_rng_LDFLAGS = $(src_test_test_LDFLAGS)
+src_test_test_rng_LDADD = $(src_test_test_LDADD)
+
src_test_test_memwipe_CPPFLAGS = $(src_test_test_CPPFLAGS)
# Don't use bugtrap cflags here: memwipe tests require memory violations.
src_test_test_memwipe_CFLAGS = $(TEST_CFLAGS)
@@ -267,22 +342,22 @@ src_test_test_memwipe_LDFLAGS = $(src_test_test_LDFLAGS) @CFLAGS_BUGTRAP@
src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
src_test_bench_LDADD = \
- $(TOR_INTERNAL_LIBS) \
+ libtor.a \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
src_test_test_workqueue_LDADD = \
- $(TOR_INTERNAL_TESTING_LIBS) \
+ src/test/libtor-testing.a \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_timers_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_timers_CFLAGS = $(src_test_test_CFLAGS)
@@ -292,17 +367,23 @@ src_test_test_timers_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_LZMA_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_TRACE_LIBS@
src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
+# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS+= \
src/test/fakechans.h \
+ src/test/fakecircs.h \
src/test/hs_test_helpers.h \
src/test/log_test_helpers.h \
+ src/test/opts_test_helpers.h \
src/test/rend_test_helpers.h \
+ src/test/resolve_test_helpers.h \
+ src/test/rng_test_helpers.h \
src/test/test.h \
+ src/test/ptr_helpers.h \
src/test/test_helpers.h \
src/test/test_dir_common.h \
src/test/test_connection.h \
@@ -320,20 +401,21 @@ noinst_PROGRAMS+= src/test/test-hs-ntor-cl
src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c
src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB)
src_test_test_ntor_cl_LDADD = \
- $(TOR_INTERNAL_LIBS) \
+ libtor.a \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
- @CURVE25519_LIBS@ @TOR_LZMA_LIBS@
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @CURVE25519_LIBS@ @TOR_LZMA_LIBS@ @TOR_TRACE_LIBS@
src_test_test_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
src_test_test_hs_ntor_cl_SOURCES = src/test/test_hs_ntor_cl.c
src_test_test_hs_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB)
src_test_test_hs_ntor_cl_LDADD = \
- $(TOR_INTERNAL_LIBS) \
+ libtor.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ \
+ @CURVE25519_LIBS@ @TOR_TRACE_LIBS@
src_test_test_hs_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
@@ -345,7 +427,8 @@ src_test_test_bt_cl_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_LIB_MATH@ \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @TOR_TRACE_LIBS@
src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS)
endif
@@ -360,7 +443,10 @@ EXTRA_DIST += \
src/test/slownacl_curve25519.py \
src/test/test_rebind.sh \
src/test/test_rebind.py \
+ src/test/test_include.sh \
+ src/test/test_include.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 \
@@ -375,6 +461,8 @@ EXTRA_DIST += \
src/test/test_workqueue_pipe.sh \
src/test/test_workqueue_pipe2.sh \
src/test/test_workqueue_socketpair.sh \
+ src/test/test_cmdline.sh \
+ src/test/test_parseconf.sh \
src/test/unittest_part1.sh \
src/test/unittest_part2.sh \
src/test/unittest_part3.sh \
diff --git a/src/test/log_test_helpers.c b/src/test/log_test_helpers.c
index 03c52dd6bd..5e60d6b282 100644
--- a/src/test/log_test_helpers.c
+++ b/src/test/log_test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define LOG_PRIVATE
#include "lib/log/log.h"
diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h
index 5d1c3c1914..c2d71c6bcd 100644
--- a/src/test/log_test_helpers.h
+++ b/src/test/log_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.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/ntor_ref.py b/src/test/ntor_ref.py
index 204f05e2ad..e3307430e1 100755
--- a/src/test/ntor_ref.py
+++ b/src/test/ntor_ref.py
@@ -27,6 +27,11 @@ commands:
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import binascii
try:
import curve25519
@@ -99,7 +104,7 @@ else:
def int2byte(i):
return bytes([i])
-def kdf_rfc5869(key, salt, info, n):
+def kdf_rfc5869(key, salt, info, n):
prk = HMAC(key=salt, msg=key)
diff --git a/src/test/ope_ref.py b/src/test/ope_ref.py
index f9bd97c546..61a86b57bb 100644
--- a/src/test/ope_ref.py
+++ b/src/test/ope_ref.py
@@ -1,9 +1,14 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
# Copyright 2018-2019, The Tor Project, Inc. See LICENSE for licensing info.
# Reference implementation for our rudimentary OPE code, used to
# generate test vectors. See crypto_ope.c for more details.
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.backends import default_backend
diff --git a/src/test/opts_test_helpers.c b/src/test/opts_test_helpers.c
new file mode 100644
index 0000000000..619ca40733
--- /dev/null
+++ b/src/test/opts_test_helpers.c
@@ -0,0 +1,38 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file opts_testing_helpers.c
+ * @brief Helper functions to access module-specific config options.
+ **/
+
+#include "orconfig.h"
+#include "test/opts_test_helpers.h"
+
+#define CONFIG_PRIVATE
+#include "core/or/or.h"
+#include "lib/confmgt/confmgt.h"
+#include "app/main/subsysmgr.h"
+#include "app/config/config.h"
+
+#include "lib/crypt_ops/crypto_sys.h"
+#include "feature/dirauth/dirauth_sys.h"
+
+struct dirauth_options_t *
+get_dirauth_options(struct or_options_t *opt)
+{
+ int idx = subsystems_get_options_idx(&sys_dirauth);
+ tor_assert(idx >= 0);
+ return config_mgr_get_obj_mutable(get_options_mgr(), opt, idx);
+}
+
+struct crypto_options_t *
+get_crypto_options(struct or_options_t *opt)
+{
+ int idx = subsystems_get_options_idx(&sys_crypto);
+ tor_assert(idx >= 0);
+ return config_mgr_get_obj_mutable(get_options_mgr(), opt, idx);
+}
diff --git a/src/test/opts_test_helpers.h b/src/test/opts_test_helpers.h
new file mode 100644
index 0000000000..f925194e63
--- /dev/null
+++ b/src/test/opts_test_helpers.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file opts_testing_helpers.h
+ * @brief Header for test/opts_test_helpers.c
+ **/
+
+#ifndef TOR_TEST_OPTS_TESTING_HELPERS_H
+#define TOR_TEST_OPTS_TESTING_HELPERS_H
+
+struct crypto_options_t;
+struct dirauth_options_t;
+struct or_options_t;
+
+struct crypto_options_t *get_crypto_options(struct or_options_t *opt);
+struct dirauth_options_t *get_dirauth_options(struct or_options_t *opt);
+
+#endif /* !defined(TOR_TEST_OPTS_TESTING_HELPERS_H) */
diff --git a/src/test/prob_distr_mpfr_ref.c b/src/test/prob_distr_mpfr_ref.c
new file mode 100644
index 0000000000..de4179c4e0
--- /dev/null
+++ b/src/test/prob_distr_mpfr_ref.c
@@ -0,0 +1,64 @@
+/* Copyright 2012-2020, The Tor Project, Inc
+ * See LICENSE for licensing information */
+
+/** prob_distr_mpfr_ref.c
+ *
+ * Example reference file for GNU MPFR vectors tested in test_prob_distr.c .
+ * Code by Riastradh.
+ */
+
+#include <complex.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+/* Must come after <stdio.h> so we get mpfr_printf. */
+#include <mpfr.h>
+
+/* gcc -o mpfr prob_distr_mpfr_ref.c -lmpfr -lm */
+
+/* Computes logit(p) for p = .49999 */
+int
+main(void)
+{
+ mpfr_t p, q, r;
+ mpfr_init(p);
+ mpfr_set_prec(p, 200);
+ mpfr_init(q);
+ mpfr_set_prec(q, 200);
+ mpfr_init(r);
+ mpfr_set_prec(r, 200);
+ mpfr_set_d(p, .49999, MPFR_RNDN);
+ mpfr_set_d(q, 1, MPFR_RNDN);
+ /* r := q - p = 1 - p */
+ mpfr_sub(r, q, p, MPFR_RNDN);
+ /* q := p/r = p/(1 - p) */
+ mpfr_div(q, p, r, MPFR_RNDN);
+ /* r := log(q) = log(p/(1 - p)) */
+ mpfr_log(r, q, MPFR_RNDN);
+ mpfr_printf("mpfr 200-bit\t%.128Rg\n", r);
+
+ /*
+ * Print a double approximation to logit three different ways. All
+ * three agree bit for bit on the libms I tried, with the nextafter
+ * adjustment (which is well within the 10 eps relative error bound
+ * advertised). Apparently I must have used the Goldberg expression
+ * for what I wrote down in the test case.
+ */
+ printf("mpfr 53-bit\t%.17g\n", nextafter(mpfr_get_d(r, MPFR_RNDN), 0), 0);
+ volatile double p0 = .49999;
+ printf("log1p\t\t%.17g\n", nextafter(-log1p((1 - 2*p0)/p0), 0));
+ volatile double x = (1 - 2*p0)/p0;
+ volatile double xp1 = x + 1;
+ printf("Goldberg\t%.17g\n", -x*log(xp1)/(xp1 - 1));
+
+ /*
+ * Print a bad approximation, using the naive expression, to see a
+ * lot of wrong digits, far beyond the 10 eps relative error attained
+ * by -log1p((1 - 2*p)/p).
+ */
+ printf("naive\t\t%.17g\n", log(p0/(1 - p0)));
+
+ fflush(stdout);
+ return ferror(stdout);
+}
diff --git a/src/test/ptr_helpers.c b/src/test/ptr_helpers.c
new file mode 100644
index 0000000000..0e0995df7c
--- /dev/null
+++ b/src/test/ptr_helpers.c
@@ -0,0 +1,50 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "test/ptr_helpers.h"
+
+/**
+ * Cast <b> (inptr_t value) to a void pointer.
+ */
+void *
+cast_intptr_to_voidstar(intptr_t x)
+{
+ void *r = (void *)x;
+
+ return r;
+}
+
+/**
+ * Cast x (void pointer) to inptr_t value.
+ */
+intptr_t
+cast_voidstar_to_intptr(void *x)
+{
+ intptr_t r = (intptr_t)x;
+
+ return r;
+}
+
+/**
+ * Cast x (uinptr_t value) to void pointer.
+ */
+void *
+cast_uintptr_to_voidstar(uintptr_t x)
+{
+ void *r = (void *)x;
+
+ return r;
+}
+
+/**
+ * Cast x (void pointer) to uinptr_t value.
+ */
+uintptr_t
+cast_voidstar_to_uintptr(void *x)
+{
+ uintptr_t r = (uintptr_t)x;
+
+ return r;
+}
diff --git a/src/test/ptr_helpers.h b/src/test/ptr_helpers.h
new file mode 100644
index 0000000000..0999fdf5d2
--- /dev/null
+++ b/src/test/ptr_helpers.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_PTR_HELPERS_H
+#define TOR_PTR_HELPERS_H
+
+#include <stdint.h>
+
+void *
+cast_intptr_to_voidstar(intptr_t x);
+
+intptr_t
+cast_voidstar_to_intptr(void *x);
+
+void *
+cast_uintptr_to_voidstar(uintptr_t x);
+
+uintptr_t
+cast_voidstar_to_uintptr(void *x);
+
+#endif /* !defined(TOR_PTR_HELPERS_H) */
diff --git a/src/test/rend_test_helpers.c b/src/test/rend_test_helpers.c
index f12d193cc5..8e40167aeb 100644
--- a/src/test/rend_test_helpers.c
+++ b/src/test/rend_test_helpers.c
@@ -1,7 +1,8 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
+#include "core/or/extendinfo.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "test/test.h"
#include "feature/rend/rendcommon.h"
@@ -58,7 +59,8 @@ create_descriptor(rend_service_descriptor_t **generated, char **service_id,
for (i = 0; i < intro_points; i++) {
rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t));
crypto_pk_t *okey = pk_generate(2 + i);
- intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ intro->extend_info =
+ extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
intro->extend_info->onion_key = okey;
crypto_pk_get_digest(intro->extend_info->onion_key,
intro->extend_info->identity_digest);
@@ -66,8 +68,12 @@ create_descriptor(rend_service_descriptor_t **generated, char **service_id,
base16_encode(intro->extend_info->nickname + 1,
sizeof(intro->extend_info->nickname) - 1,
intro->extend_info->identity_digest, DIGEST_LEN);
- tor_addr_from_ipv4h(&intro->extend_info->addr, crypto_rand_int(65536));
- intro->extend_info->port = 1 + crypto_rand_int(65535);
+ tor_addr_t addr;
+ uint16_t port;
+ /* Does not cover all IP addresses. */
+ tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1);
+ port = 1 + crypto_rand_int(65535);
+ extend_info_add_orport(intro->extend_info, &addr, port);
intro->intro_key = crypto_pk_dup_key(pk2);
smartlist_add((*generated)->intro_nodes, intro);
}
@@ -91,4 +97,3 @@ mock_rend_data(const char *onion_address)
DIGEST_LEN));
return rend_query;
}
-
diff --git a/src/test/rend_test_helpers.h b/src/test/rend_test_helpers.h
index c10da52cd7..b1078ce866 100644
--- a/src/test/rend_test_helpers.h
+++ b/src/test/rend_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/resolve_test_helpers.c b/src/test/resolve_test_helpers.c
new file mode 100644
index 0000000000..ed5853c359
--- /dev/null
+++ b/src/test/resolve_test_helpers.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file resolve_test_helpers.c
+ * @brief Helper functions for mocking libc's blocking hostname lookup
+ * facilities.
+ **/
+
+#define RESOLVE_PRIVATE
+#include "orconfig.h"
+#include "test/resolve_test_helpers.h"
+#include "lib/net/address.h"
+#include "lib/net/resolve.h"
+#include "test/test.h"
+
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * Mock replacement for our getaddrinfo/gethostbyname wrapper.
+ **/
+static int
+replacement_host_lookup(const char *name, uint16_t family, tor_addr_t *addr)
+{
+ static const struct lookup_table_ent {
+ const char *name;
+ const char *ipv4;
+ const char *ipv6;
+ } entries[] = {
+ { "localhost", "127.0.0.1", "::1" },
+ { "torproject.org", "198.51.100.6", "2001:DB8::700" },
+ { NULL, NULL, NULL },
+ };
+
+ int r = -1;
+
+ for (unsigned i = 0; entries[i].name != NULL; ++i) {
+ if (!strcasecmp(name, entries[i].name)) {
+ if (family == AF_INET6) {
+ int s = tor_addr_parse(addr, entries[i].ipv6);
+ tt_int_op(s, OP_EQ, AF_INET6);
+ } else {
+ int s = tor_addr_parse(addr, entries[i].ipv4);
+ tt_int_op(s, OP_EQ, AF_INET);
+ }
+ r = 0;
+ break;
+ }
+ }
+
+ log_debug(LD_GENERAL, "resolve(%s,%d) => %s",
+ name, family, r == 0 ? fmt_addr(addr) : "-1");
+
+ return r;
+ done:
+ return -1;
+}
+
+/**
+ * Set up a mock replacement for our wrapper on libc's resolver code.
+ *
+ * According to our replacement, only "localhost" and "torproject.org"
+ * are real addresses; everything else doesn't exist.
+ *
+ * Use this function to avoid using the DNS resolver during unit tests;
+ * call unmock_hostname_resolver() when you're done.
+ **/
+void
+mock_hostname_resolver(void)
+{
+ MOCK(tor_addr_lookup_host_impl, replacement_host_lookup);
+}
+
+/**
+ * Unmock our wrappers for libc's blocking hostname resolver code.
+ **/
+void
+unmock_hostname_resolver(void)
+{
+ UNMOCK(tor_addr_lookup_host_impl);
+}
diff --git a/src/test/resolve_test_helpers.h b/src/test/resolve_test_helpers.h
new file mode 100644
index 0000000000..ca642d6c63
--- /dev/null
+++ b/src/test/resolve_test_helpers.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file resolve_test_helpers.h
+ * @brief Header for test/resolve_test_helpers.c
+ **/
+
+#ifndef TOR_TEST_RESOLVE_TEST_HELPERS_H
+#define TOR_TEST_RESOLVE_TEST_HELPERS_H
+
+void mock_hostname_resolver(void);
+void unmock_hostname_resolver(void);
+
+#endif /* !defined(TOR_TEST_RESOLVE_TEST_HELPERS_H) */
diff --git a/src/test/rng_test_helpers.c b/src/test/rng_test_helpers.c
new file mode 100644
index 0000000000..b7d7cb0dfa
--- /dev/null
+++ b/src/test/rng_test_helpers.c
@@ -0,0 +1,259 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file rng_test_helpers.c
+ * \brief Helpers for overriding PRNGs during unit tests.
+ *
+ * We define two PRNG overrides: a "reproducible PRNG" where the seed is
+ * chosen randomly but the stream can be replayed later on in case a bug is
+ * found, and a "deterministic PRNG" where the seed is fixed in the unit
+ * tests.
+ *
+ * Obviously, this code is testing-only.
+ */
+
+#include "orconfig.h"
+#include "core/or/or.h"
+
+#include "lib/crypt_ops/crypto_rand.h"
+#include "ext/tinytest.h"
+
+#include "test/rng_test_helpers.h"
+
+#ifndef TOR_UNIT_TESTS
+#error "No. Never link this code into Tor proper."
+#endif
+
+/**
+ * True iff the RNG is currently replaced. Prevents double-replacement.
+ **/
+static bool rng_is_replaced = false;
+
+/**
+ * Mutex to protect deterministic prng.
+ *
+ * Note that if you actually _use_ the prng from two threads at the same time,
+ * the results will probably be nondeterministic anyway.
+ */
+static tor_mutex_t *rng_mutex = NULL;
+
+/**
+ * Cached old value for the thread prng.
+ **/
+static crypto_fast_rng_t *stored_fast_rng = NULL;
+
+/** replacement for crypto_strongest_rand that delegates to crypto_rand. */
+static void
+mock_crypto_strongest_rand(uint8_t *out, size_t len)
+{
+ crypto_rand((char *)out, len);
+}
+
+/* This is the seed of the deterministic randomness. */
+static uint8_t rng_seed[16];
+static crypto_xof_t *rng_xof = NULL;
+
+/**
+ * Print the seed for our PRNG to stdout. We use this when we're failed
+ * test that had a reproducible RNG set.
+ **/
+void
+testing_dump_reproducible_rng_seed(void)
+{
+ printf("\n"
+ "Seed: %s\n",
+ hex_str((const char*)rng_seed, sizeof(rng_seed)));
+}
+
+/** Produce deterministic randomness for the stochastic tests using the global
+ * rng_xof output.
+ *
+ * This function produces deterministic data over multiple calls iff it's
+ * called in the same call order with the same 'n' parameter.
+ * If not, outputs will deviate. */
+static void
+crypto_rand_deterministic(char *out, size_t n)
+{
+ tor_assert(rng_xof);
+ tor_mutex_acquire(rng_mutex);
+ crypto_xof_squeeze_bytes(rng_xof, (uint8_t*)out, n);
+ tor_mutex_release(rng_mutex);
+}
+
+/**
+ * Implementation helper: override our crypto_rand() PRNG with a given seed of
+ * length <b>seed_len</b>. Overlong seeds are truncated; short ones are
+ * padded.
+ **/
+static void
+enable_deterministic_rng_impl(const uint8_t *seed, size_t seed_len)
+{
+ tor_assert(!rng_is_replaced);
+ tor_assert(crypto_rand == crypto_rand__real);
+
+ memset(rng_seed, 0, sizeof(rng_seed));
+ memcpy(rng_seed, seed, MIN(seed_len, sizeof(rng_seed)));
+
+ rng_mutex = tor_mutex_new();
+
+ crypto_xof_free(rng_xof);
+ rng_xof = crypto_xof_new();
+ crypto_xof_add_bytes(rng_xof, rng_seed, sizeof(rng_seed));
+ MOCK(crypto_rand, crypto_rand_deterministic);
+ MOCK(crypto_strongest_rand_, mock_crypto_strongest_rand);
+
+ uint8_t fast_rng_seed[CRYPTO_FAST_RNG_SEED_LEN];
+ memset(fast_rng_seed, 0xff, sizeof(fast_rng_seed));
+ memcpy(fast_rng_seed, rng_seed, MIN(sizeof(rng_seed),
+ sizeof(fast_rng_seed)));
+ crypto_fast_rng_t *fast_rng = crypto_fast_rng_new_from_seed(fast_rng_seed);
+ crypto_fast_rng_disable_reseed(fast_rng);
+ stored_fast_rng = crypto_replace_thread_fast_rng(fast_rng);
+
+ rng_is_replaced = true;
+}
+
+/**
+ * Replace our get_thread_fast_rng(), crypto_rand() and
+ * crypto_strongest_rand() prngs with a variant that generates all of its
+ * output deterministically from a randomly chosen seed. In the event of an
+ * error, you can log the seed later on with
+ * testing_dump_reproducible_rng_seed.
+ **/
+void
+testing_enable_reproducible_rng(void)
+{
+ const char *provided_seed = getenv("TOR_TEST_RNG_SEED");
+ if (provided_seed) {
+ size_t hexlen = strlen(provided_seed);
+ size_t seedlen = hexlen / 2;
+ uint8_t *seed = tor_malloc(hexlen / 2);
+ if (base16_decode((char*)seed, seedlen, provided_seed, hexlen) < 0) {
+ puts("Cannot decode value in TOR_TEST_RNG_SEED");
+ exit(1);
+ }
+ enable_deterministic_rng_impl(seed, seedlen);
+ tor_free(seed);
+ } else {
+ uint8_t seed[16];
+ crypto_rand((char*)seed, sizeof(seed));
+ enable_deterministic_rng_impl(seed, sizeof(seed));
+ }
+}
+
+/**
+ * Replace our get_thread_fast_rng(), crypto_rand() and
+ * crypto_strongest_rand() prngs with a variant that generates all of its
+ * output deterministically from a fixed seed. This variant is mainly useful
+ * for cases when we don't want coverage to change between runs.
+ *
+ * USAGE NOTE: Test correctness SHOULD NOT depend on the specific output of
+ * this "rng". If you need a specific output, use
+ * testing_enable_prefilled_rng() instead.
+ **/
+void
+testing_enable_deterministic_rng(void)
+{
+ static const uint8_t quotation[] =
+ "What will it be? A tree? A weed? "
+ "Each one is started from a seed."; // -- Mary Ann Hoberman
+ enable_deterministic_rng_impl(quotation, sizeof(quotation));
+}
+
+static uint8_t *prefilled_rng_buffer = NULL;
+static size_t prefilled_rng_buflen;
+static size_t prefilled_rng_idx;
+
+/**
+ * crypto_rand() replacement that returns canned data.
+ **/
+static void
+crypto_rand_prefilled(char *out, size_t n)
+{
+ tor_mutex_acquire(rng_mutex);
+ while (n) {
+ size_t n_to_copy = MIN(prefilled_rng_buflen - prefilled_rng_idx, n);
+ memcpy(out, prefilled_rng_buffer + prefilled_rng_idx, n_to_copy);
+ out += n_to_copy;
+ n -= n_to_copy;
+ prefilled_rng_idx += n_to_copy;
+
+ if (prefilled_rng_idx == prefilled_rng_buflen) {
+ prefilled_rng_idx = 0;
+ }
+ }
+ tor_mutex_release(rng_mutex);
+}
+
+/**
+ * Replace our crypto_rand() and crypto_strongest_rand() prngs with a variant
+ * that yields output from a buffer. If it reaches the end of the buffer, it
+ * starts over.
+ *
+ * Note: the get_thread_fast_rng() prng is not replaced by this; we'll need
+ * more code to support that.
+ **/
+void
+testing_enable_prefilled_rng(const void *buffer, size_t buflen)
+{
+ tor_assert(buflen > 0);
+ tor_assert(!rng_mutex);
+ rng_mutex = tor_mutex_new();
+
+ tor_mutex_acquire(rng_mutex);
+
+ prefilled_rng_buffer = tor_memdup(buffer, buflen);
+ prefilled_rng_buflen = buflen;
+ prefilled_rng_idx = 0;
+
+ tor_mutex_release(rng_mutex);
+
+ MOCK(crypto_rand, crypto_rand_prefilled);
+ MOCK(crypto_strongest_rand_, mock_crypto_strongest_rand);
+}
+
+/**
+ * Reset the position in the prefilled RNG buffer to the start.
+ */
+void
+testing_prefilled_rng_reset(void)
+{
+ tor_mutex_acquire(rng_mutex);
+ prefilled_rng_idx = 0;
+ tor_mutex_release(rng_mutex);
+}
+
+/**
+ * Undo the overrides for our PRNG. To be used at the end of testing.
+ *
+ * Note that this function should be safe to call even if the rng has not
+ * yet been replaced.
+ **/
+void
+testing_disable_rng_override(void)
+{
+ crypto_xof_free(rng_xof);
+ tor_free(prefilled_rng_buffer);
+ UNMOCK(crypto_rand);
+ UNMOCK(crypto_strongest_rand_);
+ tor_mutex_free(rng_mutex);
+
+ crypto_fast_rng_t *rng = crypto_replace_thread_fast_rng(stored_fast_rng);
+ crypto_fast_rng_free(rng);
+
+ rng_is_replaced = false;
+}
+
+/**
+ * As testing_disable_rng_override(), but dump the seed if the current
+ * test has failed.
+ */
+void
+testing_disable_reproducible_rng(void)
+{
+ if (tinytest_cur_test_has_failed()) {
+ testing_dump_reproducible_rng_seed();
+ }
+ testing_disable_rng_override();
+}
diff --git a/src/test/rng_test_helpers.h b/src/test/rng_test_helpers.h
new file mode 100644
index 0000000000..6fcdaa2653
--- /dev/null
+++ b/src/test/rng_test_helpers.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_RNG_TEST_HELPERS_H
+#define TOR_RNG_TEST_HELPERS_H
+
+#include "core/or/or.h"
+
+void testing_enable_deterministic_rng(void);
+void testing_enable_reproducible_rng(void);
+void testing_enable_prefilled_rng(const void *buffer, size_t buflen);
+
+void testing_prefilled_rng_reset(void);
+
+void testing_disable_rng_override(void);
+
+void testing_disable_reproducible_rng(void);
+#define testing_disable_deterministic_rng() \
+ testing_disable_rng_override()
+#define testing_disable_prefilled_rng() \
+ testing_disable_rng_override()
+
+void testing_dump_reproducible_rng_seed(void);
+
+#endif /* !defined(TOR_RNG_TEST_HELPERS_H) */
diff --git a/src/test/slow_ed25519.py b/src/test/slow_ed25519.py
index f44708b200..df1456b811 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
@@ -8,6 +8,11 @@
#
# Don't edit this file. Mess with ed25519_ref.py
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import hashlib
b = 256
@@ -19,7 +24,7 @@ def H(m):
def expmod(b,e,m):
if e == 0: return 1
- t = expmod(b,e/2,m)**2 % m
+ t = expmod(b,e//2,m)**2 % m
if e & 1: t = (t*b) % m
return t
@@ -27,11 +32,11 @@ def inv(x):
return expmod(x,q-2,q)
d = -121665 * inv(121666)
-I = expmod(2,(q-1)/4,q)
+I = expmod(2,(q-1)//4,q)
def xrecover(y):
xx = (y*y-1) * inv(d*y*y+1)
- x = expmod(xx,(q+3)/8,q)
+ x = expmod(xx,(q+3)//8,q)
if (x*x - xx) % q != 0: x = (x*I) % q
if x % 2 != 0: x = q-x
return x
@@ -51,23 +56,23 @@ def edwards(P,Q):
def scalarmult(P,e):
if e == 0: return [0,1]
- Q = scalarmult(P,e/2)
+ Q = scalarmult(P,e//2)
Q = edwards(Q,Q)
if e & 1: Q = edwards(Q,P)
return Q
def encodeint(y):
bits = [(y >> i) & 1 for i in range(b)]
- return ''.join([chr(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b/8)])
+ return bytes(sum([bits[i * 8 + j] << j for j in range(8)]) for i in range(b//8))
def encodepoint(P):
x = P[0]
y = P[1]
bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1]
- return ''.join([chr(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b/8)])
+ return bytes([(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b//8)])
def bit(h,i):
- return (ord(h[i/8]) >> (i%8)) & 1
+ return (h[i//8] >> (i%8)) & 1
def publickey(sk):
h = H(sk)
@@ -82,7 +87,7 @@ def Hint(m):
def signature(m,sk,pk):
h = H(sk)
a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
- r = Hint(''.join([h[i] for i in range(b/8,b/4)]) + m)
+ r = Hint(bytes([h[i] for i in range(b//8,b//4)]) + m)
R = scalarmult(B,r)
S = (r + Hint(encodepoint(R) + pk + m) * a) % l
return encodepoint(R) + encodeint(S)
@@ -104,12 +109,11 @@ def decodepoint(s):
return P
def checkvalid(s,m,pk):
- if len(s) != b/4: raise Exception("signature length is wrong")
- if len(pk) != b/8: raise Exception("public-key length is wrong")
- R = decodepoint(s[0:b/8])
+ if len(s) != b//4: raise Exception("signature length is wrong")
+ if len(pk) != b//8: raise Exception("public-key length is wrong")
+ R = decodepoint(s[0:b//8])
A = decodepoint(pk)
- S = decodeint(s[b/8:b/4])
+ S = decodeint(s[b//8:b//4])
h = Hint(encodepoint(R) + pk + m)
if scalarmult(B,S) != edwards(R,scalarmult(A,h)):
raise Exception("signature does not pass verification")
-
diff --git a/src/test/slownacl_curve25519.py b/src/test/slownacl_curve25519.py
index 4dabab61b6..0cafe0e71f 100644
--- a/src/test/slownacl_curve25519.py
+++ b/src/test/slownacl_curve25519.py
@@ -6,10 +6,15 @@
# Nick got the slownacl source from:
# https://github.com/mdempsky/dnscurve/tree/master/slownacl
-__all__ = ['smult_curve25519_base', 'smult_curve25519']
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
import sys
+__all__ = ['smult_curve25519_base', 'smult_curve25519']
+
P = 2 ** 255 - 19
A = 486662
diff --git a/src/test/sr_commit_calc_ref.py b/src/test/sr_commit_calc_ref.py
index 45e629cfb0..c4cb72d87f 100644
--- a/src/test/sr_commit_calc_ref.py
+++ b/src/test/sr_commit_calc_ref.py
@@ -12,6 +12,11 @@
# COMMIT = base64-encode( TIMESTAMP || H(REVEAL) )
#
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/sr_srv_calc_ref.py b/src/test/sr_srv_calc_ref.py
index 492ca62b15..a3752b15cc 100644
--- a/src/test/sr_srv_calc_ref.py
+++ b/src/test/sr_srv_calc_ref.py
@@ -10,6 +10,11 @@
# HASHED_REVEALS | previous_SRV)
#
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/test-child.c b/src/test/test-child.c
deleted file mode 100644
index 11a1695cad..0000000000
--- a/src/test/test-child.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright (c) 2011-2019, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-#include "orconfig.h"
-#include <stdio.h>
-#ifdef _WIN32
-#define WINDOWS_LEAN_AND_MEAN
-#include <windows.h>
-#else
-#include <unistd.h>
-#endif /* defined(_WIN32) */
-#include <string.h>
-
-#ifdef _WIN32
-#define SLEEP(sec) Sleep((sec)*1000)
-#else
-#define SLEEP(sec) sleep(sec)
-#endif
-
-/** Trivial test program which prints out its command line arguments so we can
- * check if tor_spawn_background() works */
-int
-main(int argc, char **argv)
-{
- int i;
- int delay = 1;
- int fast = 0;
-
- if (argc > 1) {
- if (!strcmp(argv[1], "--hang")) {
- delay = 60;
- } else if (!strcmp(argv[1], "--fast")) {
- fast = 1;
- delay = 0;
- }
- }
-
- fprintf(stdout, "OUT\n");
- fprintf(stderr, "ERR\n");
- for (i = 1; i < argc; i++)
- fprintf(stdout, "%s\n", argv[i]);
- if (!fast)
- fprintf(stdout, "SLEEPING\n");
- /* We need to flush stdout so that test_util_spawn_background_partial_read()
- succeed. Otherwise ReadFile() will get the entire output in one */
- // XXX: Can we make stdio flush on newline?
- fflush(stdout);
- if (!fast)
- SLEEP(1);
- fprintf(stdout, "DONE\n");
- fflush(stdout);
- if (fast)
- return 0;
-
- while (--delay) {
- SLEEP(1);
- }
-
- return 0;
-}
-
diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c
index 43754ed1c2..5e4cc7678e 100644
--- a/src/test/test-memwipe.c
+++ b/src/test/test-memwipe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -30,8 +30,8 @@ const char *s = NULL;
#define BUF_LEN 2048
#define FILL_BUFFER_IMPL() \
+ do { \
unsigned int i; \
- unsigned sum = 0; \
\
/* Fill up a 1k buffer with a recognizable pattern. */ \
for (i = 0; i < BUF_LEN; i += strlen(s)) { \
@@ -42,20 +42,22 @@ const char *s = NULL;
/* optimized away. */ \
for (i = 0; i < BUF_LEN; ++i) { \
sum += (unsigned char)buf[i]; \
- }
+ } \
+ } while (0)
#ifdef OpenBSD
/* Disable some of OpenBSD's malloc protections for this test. This helps
* us do bad things, such as access freed buffers, without crashing. */
extern const char *malloc_options;
const char *malloc_options = "sufjj";
-#endif
+#endif /* defined(OpenBSD) */
static unsigned
fill_a_buffer_memset(void)
{
char buf[BUF_LEN];
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memset(buf, 0, sizeof(buf));
return sum;
}
@@ -64,7 +66,8 @@ static unsigned
fill_a_buffer_memwipe(void)
{
char buf[BUF_LEN];
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memwipe(buf, 0, sizeof(buf));
return sum;
}
@@ -73,7 +76,8 @@ static unsigned
fill_a_buffer_nothing(void)
{
char buf[BUF_LEN];
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
return sum;
}
@@ -116,7 +120,8 @@ static unsigned
fill_heap_buffer_memset(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memset(buf, 0, BUF_LEN);
raw_free(buf);
return sum;
@@ -126,7 +131,8 @@ static unsigned
fill_heap_buffer_memwipe(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memwipe(buf, 0, BUF_LEN);
raw_free(buf);
return sum;
@@ -136,7 +142,8 @@ static unsigned
fill_heap_buffer_nothing(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
raw_free(buf);
return sum;
}
diff --git a/src/test/test-network.sh b/src/test/test-network.sh
index b7a9f1b3c0..5ef995f1a4 100755
--- a/src/test/test-network.sh
+++ b/src/test/test-network.sh
@@ -5,7 +5,7 @@
# If we already know CHUTNEY_PATH, don't bother with argument parsing
TEST_NETWORK="$CHUTNEY_PATH/tools/test-network.sh"
# Call the chutney version of this script, if it exists, and we can find it
-if [ -d "$CHUTNEY_PATH" -a -x "$TEST_NETWORK" ]; then
+if [ -d "$CHUTNEY_PATH" ] && [ -x "$TEST_NETWORK" ]; then
# we can't produce any output, because we might be --quiet
# this preserves arguments with spaces correctly
exec "$TEST_NETWORK" "$@"
@@ -16,34 +16,16 @@ fi
# Do we output anything at all?
ECHO="${ECHO:-echo}"
# Output is prefixed with the name of the script
-myname=$(basename $0)
-
-# Save the arguments before we destroy them
-# This might not preserve arguments with spaces in them
-ORIGINAL_ARGS="$@"
+myname=$(basename "$0")
# We need to find CHUTNEY_PATH, so that we can call the version of this script
# in chutney/tools with the same arguments. We also need to respect --quiet.
-until [ -z "$1" ]
-do
- case "$1" in
- --chutney-path)
- CHUTNEY_PATH="$2"
- shift
- ;;
- --tor-path)
- TOR_DIR="$2"
- shift
- ;;
- --quiet)
- ECHO=true
- ;;
- *)
- # maybe chutney's test-network.sh can handle it
- ;;
- esac
- shift
-done
+CHUTNEY_PATH=$(echo "$@" | awk -F '--chutney-path ' '{sub(" .*","",$2); print $2}')
+TOR_DIR=$(echo "$@" | awk -F '--tor-dir ' '{sub(" .*","",$2); print $2}')
+
+if echo "$@" | grep -e "--quiet" > /dev/null; then
+ ECHO=true
+fi
# optional: $TOR_DIR is the tor build directory
# it's used to find the location of tor binaries
@@ -52,12 +34,12 @@ done
# - if $PWD looks like a tor build directory, set it to $PWD, or
# - unset $TOR_DIR, and let chutney fall back to finding tor binaries in $PATH
if [ ! -d "$TOR_DIR" ]; then
- if [ -d "$BUILDDIR/src/core/or" -a -d "$BUILDDIR/src/tools" ]; then
+ if [ -d "$BUILDDIR/src/core/or" ] && [ -d "$BUILDDIR/src/tools" ]; then
# Choose the build directory
# But only if it looks like one
$ECHO "$myname: \$TOR_DIR not set, trying \$BUILDDIR"
TOR_DIR="$BUILDDIR"
- elif [ -d "$PWD/src/core/or" -a -d "$PWD/src/tools" ]; then
+ elif [ -d "$PWD/src/core/or" ] && [ -d "$PWD/src/tools" ]; then
# Guess the tor directory is the current directory
# But only if it looks like one
$ECHO "$myname: \$TOR_DIR not set, trying \$PWD"
@@ -73,12 +55,12 @@ fi
# - if $PWD looks like a chutney directory, set it to $PWD, or
# - set it based on $TOR_DIR, expecting chutney to be next to tor, or
# - fail and tell the user how to clone the chutney repository
-if [ ! -d "$CHUTNEY_PATH" -o ! -x "$CHUTNEY_PATH/chutney" ]; then
+if [ ! -d "$CHUTNEY_PATH" ] || [ ! -x "$CHUTNEY_PATH/chutney" ]; then
if [ -x "$PWD/chutney" ]; then
$ECHO "$myname: \$CHUTNEY_PATH not valid, trying \$PWD"
CHUTNEY_PATH="$PWD"
- elif [ -d "$TOR_DIR" -a -d "$TOR_DIR/../chutney" -a \
- -x "$TOR_DIR/../chutney/chutney" ]; then
+ elif [ -d "$TOR_DIR" ] && [ -d "$TOR_DIR/../chutney" ] && \
+ [ -x "$TOR_DIR/../chutney/chutney" ]; then
$ECHO "$myname: \$CHUTNEY_PATH not valid, trying \$TOR_DIR/../chutney"
CHUTNEY_PATH="$TOR_DIR/../chutney"
else
@@ -94,12 +76,12 @@ fi
TEST_NETWORK="$CHUTNEY_PATH/tools/test-network.sh"
# Call the chutney version of this script, if it exists, and we can find it
-if [ -d "$CHUTNEY_PATH" -a -x "$TEST_NETWORK" ]; then
+if [ -d "$CHUTNEY_PATH" ] && [ -x "$TEST_NETWORK" ]; then
$ECHO "$myname: Calling newer chutney script $TEST_NETWORK"
# this may fail if some arguments have spaces in them
# if so, set CHUTNEY_PATH before calling test-network.sh, and spaces
# will be handled correctly
- exec "$TEST_NETWORK" $ORIGINAL_ARGS
+ exec "$TEST_NETWORK" "$@"
else
$ECHO "$myname: Could not find tools/test-network.sh in CHUTNEY_PATH."
$ECHO "$myname: Please update your chutney using 'git pull'."
diff --git a/src/test/test-process.c b/src/test/test-process.c
new file mode 100644
index 0000000000..f5a1f1a54e
--- /dev/null
+++ b/src/test/test-process.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 2011-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include <stdio.h>
+#ifdef _WIN32
+#define WINDOWS_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif /* defined(_WIN32) */
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef _WIN32
+#define SLEEP(sec) Sleep((sec)*1000)
+#else
+#define SLEEP(sec) sleep(sec)
+#endif
+
+/* Trivial test program to test process_t. */
+int
+main(int argc, char **argv)
+{
+ /* Does our process get the right arguments? */
+ for (int i = 0; i < argc; ++i) {
+ fprintf(stdout, "argv[%d] = '%s'\n", i, argv[i]);
+ fflush(stdout);
+ }
+
+ /* Make sure our process got our environment variable. */
+ fprintf(stdout, "Environment variable TOR_TEST_ENV = '%s'\n",
+ getenv("TOR_TEST_ENV"));
+ fflush(stdout);
+
+ /* Test line handling on stdout and stderr. */
+ fprintf(stdout, "Output on stdout\nThis is a new line\n");
+ fflush(stdout);
+
+ fprintf(stderr, "Output on stderr\nThis is a new line\n");
+ fflush(stderr);
+
+ fprintf(stdout, "Partial line on stdout ...");
+ fflush(stdout);
+
+ fprintf(stderr, "Partial line on stderr ...");
+ fflush(stderr);
+
+ SLEEP(2);
+
+ fprintf(stdout, "end of partial line on stdout\n");
+ fflush(stdout);
+ fprintf(stderr, "end of partial line on stderr\n");
+ fflush(stderr);
+
+ /* Echo input from stdin. */
+ char buffer[1024];
+
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ /* Strip the newline. */
+ size_t size = strlen(buffer);
+
+ if (size >= 1 && buffer[size - 1] == '\n') {
+ buffer[size - 1] = '\0';
+ --size;
+ }
+
+ if (size >= 1 && buffer[size - 1] == '\r') {
+ buffer[size - 1] = '\0';
+ --size;
+ }
+
+ fprintf(stdout, "Read line from stdin: '%s'\n", buffer);
+ fflush(stdout);
+
+ if (++count == 3)
+ break;
+ }
+
+ fprintf(stdout, "We are done for here, thank you!\n");
+
+ return 0;
+}
diff --git a/src/test/test-timers.c b/src/test/test-timers.c
index c80fb1e305..18e2191a09 100644
--- a/src/test/test-timers.c
+++ b/src/test/test-timers.c
@@ -1,4 +1,4 @@
-/* Copyright 2016-2019, The Tor Project, Inc. */
+/* Copyright 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -59,7 +59,7 @@ main(int argc, char **argv)
{
(void)argc;
(void)argv;
- tor_libevent_cfg cfg;
+ tor_libevent_cfg_t cfg;
memset(&cfg, 0, sizeof(cfg));
tor_libevent_initialize(&cfg);
timers_initialize();
diff --git a/src/test/test.c b/src/test/test.c
index 58b468775c..ffea158141 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+->a * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,6 +12,7 @@
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "app/config/or_state_st.h"
+#include "test/rng_test_helpers.h"
#include <stdio.h>
#ifdef HAVE_FCNTL_H
@@ -37,12 +38,13 @@
#include "core/or/or.h"
#include "lib/err/backtrace.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitstats.h"
#include "lib/compress/compress.h"
#include "app/config/config.h"
#include "core/or/connection_edge.h"
+#include "core/or/extendinfo.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendcache.h"
#include "feature/rend/rendparse.h"
@@ -54,7 +56,6 @@
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_tap.h"
#include "core/or/policies.h"
-#include "feature/stats/rephist.h"
#include "app/config/statefile.h"
#include "lib/crypt_ops/crypto_curve25519.h"
@@ -283,7 +284,7 @@ test_fast_handshake(void *arg)
/* First, test an entire handshake. */
memset(client_handshake, 0, sizeof(client_handshake));
tt_int_op(0, OP_EQ, fast_onionskin_create(&state, client_handshake));
- tt_assert(! tor_mem_is_zero((char*)client_handshake,
+ tt_assert(! fast_mem_is_zero((char*)client_handshake,
sizeof(client_handshake)));
tt_int_op(0, OP_EQ,
@@ -354,18 +355,6 @@ test_onion_queues(void *arg)
tor_free(onionskin);
}
-static crypto_cipher_t *crypto_rand_aes_cipher = NULL;
-
-// Mock replacement for crypto_rand: Generates bytes from a provided AES_CTR
-// cipher in <b>crypto_rand_aes_cipher</b>.
-static void
-crypto_rand_deterministic_aes(char *out, size_t n)
-{
- tor_assert(crypto_rand_aes_cipher);
- memset(out, 0, n);
- crypto_cipher_crypt_inplace(crypto_rand_aes_cipher, out, n);
-}
-
static void
test_circuit_timeout(void *arg)
{
@@ -397,8 +386,7 @@ test_circuit_timeout(void *arg)
// Use a deterministic RNG here, or else we'll get nondeterministic
// coverage in some of the circuitstats functions.
- MOCK(crypto_rand, crypto_rand_deterministic_aes);
- crypto_rand_aes_cipher = crypto_cipher_new("xyzzyplughplover");
+ testing_enable_deterministic_rng();
circuitbuild_running_unit_tests();
#define timeout0 (build_time_t)(30*1000.0)
@@ -534,8 +522,8 @@ test_circuit_timeout(void *arg)
circuit_build_times_free_timeouts(&final);
or_state_free(state);
teardown_periodic_events();
- UNMOCK(crypto_rand);
- crypto_cipher_free(crypto_rand_aes_cipher);
+
+ testing_disable_deterministic_rng();
}
/** Test encoding and parsing of rendezvous service descriptors. */
@@ -577,7 +565,8 @@ test_rend_fns(void *arg)
for (i = 0; i < 3; i++) {
rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t));
crypto_pk_t *okey = pk_generate(2 + i);
- intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ intro->extend_info =
+ extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
intro->extend_info->onion_key = okey;
crypto_pk_get_digest(intro->extend_info->onion_key,
intro->extend_info->identity_digest);
@@ -586,9 +575,12 @@ test_rend_fns(void *arg)
base16_encode(intro->extend_info->nickname + 1,
sizeof(intro->extend_info->nickname) - 1,
intro->extend_info->identity_digest, DIGEST_LEN);
+ tor_addr_t addr;
+ uint16_t port;
/* Does not cover all IP addresses. */
- tor_addr_from_ipv4h(&intro->extend_info->addr, crypto_rand_int(65536));
- intro->extend_info->port = 1 + crypto_rand_int(65535);
+ tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1);
+ port = 1 + crypto_rand_int(65535);
+ extend_info_add_orport(intro->extend_info, &addr, port);
intro->intro_key = crypto_pk_dup_key(pk2);
smartlist_add(generated->intro_nodes, intro);
}
@@ -626,8 +618,12 @@ test_rend_fns(void *arg)
tt_mem_op(gen_info->identity_digest,OP_EQ, par_info->identity_digest,
DIGEST_LEN);
tt_str_op(gen_info->nickname,OP_EQ, par_info->nickname);
- tt_assert(tor_addr_eq(&gen_info->addr, &par_info->addr));
- tt_int_op(gen_info->port,OP_EQ, par_info->port);
+ const tor_addr_port_t *a1, *a2;
+ a1 = extend_info_get_orport(gen_info, AF_INET);
+ a2 = extend_info_get_orport(par_info, AF_INET);
+ tt_assert(a1 && a2);
+ tt_assert(tor_addr_eq(&a1->addr, &a2->addr));
+ tt_int_op(a2->port,OP_EQ, a2->port);
}
rend_service_descriptor_free(parsed);
@@ -651,166 +647,6 @@ test_rend_fns(void *arg)
tor_free(intro_points_encrypted);
}
-/** Run unit tests for stats code. */
-static void
-test_stats(void *arg)
-{
- time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- char *s = NULL;
- int i;
-
- /* Start with testing exit port statistics; we shouldn't collect exit
- * stats without initializing them. */
- (void)arg;
- rep_hist_note_exit_stream_opened(80);
- rep_hist_note_exit_bytes(80, 100, 10000);
- s = rep_hist_format_exit_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Initialize stats, note some streams and bytes, and generate history
- * string. */
- rep_hist_exit_stats_init(now);
- rep_hist_note_exit_stream_opened(80);
- rep_hist_note_exit_bytes(80, 100, 10000);
- rep_hist_note_exit_stream_opened(443);
- rep_hist_note_exit_bytes(443, 100, 10000);
- rep_hist_note_exit_bytes(443, 100, 10000);
- s = rep_hist_format_exit_stats(now + 86400);
- tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "exit-kibibytes-written 80=1,443=1,other=0\n"
- "exit-kibibytes-read 80=10,443=20,other=0\n"
- "exit-streams-opened 80=4,443=4,other=0\n",OP_EQ, s);
- tor_free(s);
-
- /* Add a few bytes on 10 more ports and ensure that only the top 10
- * ports are contained in the history string. */
- for (i = 50; i < 60; i++) {
- rep_hist_note_exit_bytes(i, i, i);
- rep_hist_note_exit_stream_opened(i);
- }
- s = rep_hist_format_exit_stats(now + 86400);
- tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "exit-kibibytes-written 52=1,53=1,54=1,55=1,56=1,57=1,58=1,"
- "59=1,80=1,443=1,other=1\n"
- "exit-kibibytes-read 52=1,53=1,54=1,55=1,56=1,57=1,58=1,"
- "59=1,80=10,443=20,other=1\n"
- "exit-streams-opened 52=4,53=4,54=4,55=4,56=4,57=4,58=4,"
- "59=4,80=4,443=4,other=4\n",OP_EQ, s);
- tor_free(s);
-
- /* Stop collecting stats, add some bytes, and ensure we don't generate
- * a history string. */
- rep_hist_exit_stats_term();
- rep_hist_note_exit_bytes(80, 100, 10000);
- s = rep_hist_format_exit_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Re-start stats, add some bytes, reset stats, and see what history we
- * get when observing no streams or bytes at all. */
- rep_hist_exit_stats_init(now);
- rep_hist_note_exit_stream_opened(80);
- rep_hist_note_exit_bytes(80, 100, 10000);
- rep_hist_reset_exit_stats(now);
- s = rep_hist_format_exit_stats(now + 86400);
- tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "exit-kibibytes-written other=0\n"
- "exit-kibibytes-read other=0\n"
- "exit-streams-opened other=0\n",OP_EQ, s);
- tor_free(s);
-
- /* Continue with testing connection statistics; we shouldn't collect
- * conn stats without initializing them. */
- rep_hist_note_or_conn_bytes(1, 20, 400, now);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Initialize stats, note bytes, and generate history string. */
- rep_hist_conn_stats_init(now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n",OP_EQ, s);
- tor_free(s);
-
- /* Stop collecting stats, add some bytes, and ensure we don't generate
- * a history string. */
- rep_hist_conn_stats_term();
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Re-start stats, add some bytes, reset stats, and see what history we
- * get when observing no bytes at all. */
- rep_hist_conn_stats_init(now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- rep_hist_reset_conn_stats(now);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",OP_EQ, s);
- tor_free(s);
-
- /* Continue with testing buffer statistics; we shouldn't collect buffer
- * stats without initializing them. */
- rep_hist_add_buffer_stats(2.0, 2.0, 20);
- s = rep_hist_format_buffer_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Initialize stats, add statistics for a single circuit, and generate
- * the history string. */
- rep_hist_buffer_stats_init(now);
- rep_hist_add_buffer_stats(2.0, 2.0, 20);
- s = rep_hist_format_buffer_stats(now + 86400);
- tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "cell-processed-cells 20,0,0,0,0,0,0,0,0,0\n"
- "cell-queued-cells 2.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
- "0.00,0.00\n"
- "cell-time-in-queue 2,0,0,0,0,0,0,0,0,0\n"
- "cell-circuits-per-decile 1\n",OP_EQ, s);
- tor_free(s);
-
- /* Add nineteen more circuit statistics to the one that's already in the
- * history to see that the math works correctly. */
- for (i = 21; i < 30; i++)
- rep_hist_add_buffer_stats(2.0, 2.0, i);
- for (i = 20; i < 30; i++)
- rep_hist_add_buffer_stats(3.5, 3.5, i);
- s = rep_hist_format_buffer_stats(now + 86400);
- tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "cell-processed-cells 29,28,27,26,25,24,23,22,21,20\n"
- "cell-queued-cells 2.75,2.75,2.75,2.75,2.75,2.75,2.75,2.75,"
- "2.75,2.75\n"
- "cell-time-in-queue 3,3,3,3,3,3,3,3,3,3\n"
- "cell-circuits-per-decile 2\n",OP_EQ, s);
- tor_free(s);
-
- /* Stop collecting stats, add statistics for one circuit, and ensure we
- * don't generate a history string. */
- rep_hist_buffer_stats_term();
- rep_hist_add_buffer_stats(2.0, 2.0, 20);
- s = rep_hist_format_buffer_stats(now + 86400);
- tt_ptr_op(s, OP_EQ, NULL);
-
- /* Re-start stats, add statistics for one circuit, reset stats, and make
- * sure that the history has all zeros. */
- rep_hist_buffer_stats_init(now);
- rep_hist_add_buffer_stats(2.0, 2.0, 20);
- rep_hist_reset_buffer_stats(now);
- s = rep_hist_format_buffer_stats(now + 86400);
- tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "cell-processed-cells 0,0,0,0,0,0,0,0,0,0\n"
- "cell-queued-cells 0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
- "0.00,0.00\n"
- "cell-time-in-queue 0,0,0,0,0,0,0,0,0,0\n"
- "cell-circuits-per-decile 0\n",OP_EQ, s);
-
- done:
- tor_free(s);
-}
-
#define ENT(name) \
{ #name, test_ ## name , 0, NULL, NULL }
#define FORK(name) \
@@ -824,7 +660,6 @@ static struct testcase_t test_array[] = {
{ "fast_handshake", test_fast_handshake, 0, NULL, NULL },
FORK(circuit_timeout),
FORK(rend_fns),
- FORK(stats),
END_OF_TESTCASES
};
@@ -845,18 +680,24 @@ struct testgroup_t testgroups[] = {
{ "channeltls/", channeltls_tests },
{ "checkdir/", checkdir_tests },
{ "circuitbuild/", circuitbuild_tests },
+ { "circuitpadding/", circuitpadding_tests },
{ "circuitlist/", circuitlist_tests },
{ "circuitmux/", circuitmux_tests },
- { "circuituse/", circuituse_tests },
+ { "circuitmux_ewma/", circuitmux_ewma_tests },
{ "circuitstats/", circuitstats_tests },
+ { "circuituse/", circuituse_tests },
{ "compat/libevent/", compat_libevent_tests },
{ "config/", config_tests },
+ { "config/mgr/", confmgr_tests },
+ { "config/parse/", confparse_tests },
{ "connection/", connection_tests },
{ "conscache/", conscache_tests },
{ "consdiff/", consdiff_tests },
{ "consdiffmgr/", consdiffmgr_tests },
{ "container/", container_tests },
+ { "container/namemap/", namemap_tests },
{ "control/", controller_tests },
+ { "control/btrack/", btrack_tests },
{ "control/event/", controller_event_tests },
{ "crypto/", crypto_tests },
{ "crypto/ope/", crypto_ope_tests },
@@ -864,42 +705,60 @@ struct testgroup_t testgroups[] = {
{ "crypto/openssl/", crypto_openssl_tests },
#endif
{ "crypto/pem/", pem_tests },
+ { "crypto/rng/", crypto_rng_tests },
{ "dir/", dir_tests },
- { "dir_handle_get/", dir_handle_get_tests },
+ { "dir/auth/process_descs/", process_descs_tests },
{ "dir/md/", microdesc_tests },
- { "dir/voting-schedule/", voting_schedule_tests },
+ { "dirauth/dirvote/", dirvote_tests},
+ { "dir/voting/flags/", voting_flags_tests },
+ { "dir/voting/schedule/", voting_schedule_tests },
+ { "dir_handle_get/", dir_handle_get_tests },
+ { "dispatch/", dispatch_tests, },
+ { "dns/", dns_tests },
{ "dos/", dos_tests },
{ "entryconn/", entryconn_tests },
{ "entrynodes/", entrynodes_tests },
- { "guardfraction/", guardfraction_tests },
{ "extorport/", extorport_tests },
{ "geoip/", geoip_tests },
- { "legacy_hs/", hs_tests },
+ { "guardfraction/", guardfraction_tests },
{ "hs_cache/", hs_cache },
{ "hs_cell/", hs_cell_tests },
+ { "hs_client/", hs_client_tests },
{ "hs_common/", hs_common_tests },
{ "hs_config/", hs_config_tests },
{ "hs_control/", hs_control_tests },
{ "hs_descriptor/", hs_descriptor },
+ { "hs_dos/", hs_dos_tests },
+ { "hs_intropoint/", hs_intropoint_tests },
+ { "hs_metrics/", hs_metrics_tests },
{ "hs_ntor/", hs_ntor_tests },
+ { "hs_ob/", hs_ob_tests },
{ "hs_service/", hs_service_tests },
- { "hs_client/", hs_client_tests },
- { "hs_intropoint/", hs_intropoint_tests },
{ "introduce/", introduce_tests },
{ "keypin/", keypin_tests },
+ { "legacy_hs/", hs_tests },
{ "link-handshake/", link_handshake_tests },
{ "mainloop/", mainloop_tests },
+ { "metrics/", metrics_tests },
+ { "netinfo/", netinfo_tests },
{ "nodelist/", nodelist_tests },
{ "oom/", oom_tests },
{ "oos/", oos_tests },
{ "options/", options_tests },
+ { "options/act/", options_act_tests },
+ { "parsecommon/", parsecommon_tests },
{ "periodic-event/" , periodic_event_tests },
{ "policy/" , policy_tests },
+ { "prob_distr/", prob_distr_tests },
{ "procmon/", procmon_tests },
+ { "process/", process_tests },
+ { "proto/haproxy/", proto_haproxy_tests },
{ "proto/http/", proto_http_tests },
{ "proto/misc/", proto_misc_tests },
{ "protover/", protover_tests },
{ "pt/", pt_tests },
+ { "pubsub/build/", pubsub_build_tests },
+ { "pubsub/msg/", pubsub_msg_tests },
{ "relay/" , relay_tests },
{ "relaycell/", relaycell_tests },
{ "relaycrypt/", relaycrypt_tests },
@@ -910,10 +769,14 @@ struct testgroup_t testgroups[] = {
{ "routerlist/", routerlist_tests },
{ "routerset/" , routerset_tests },
{ "scheduler/", scheduler_tests },
- { "socks/", socks_tests },
+ { "sendme/", sendme_tests },
{ "shared-random/", sr_tests },
+ { "socks/", socks_tests },
+ { "statefile/", statefile_tests },
+ { "stats/", stats_tests },
{ "status/" , status_tests },
{ "storagedir/", storagedir_tests },
+ { "token_bucket/", token_bucket_tests },
{ "tortls/", tortls_tests },
#ifndef ENABLE_NSS
{ "tortls/openssl/", tortls_openssl_tests },
@@ -921,10 +784,9 @@ struct testgroup_t testgroups[] = {
{ "tortls/x509/", x509_tests },
{ "util/", util_tests },
{ "util/format/", util_format_tests },
+ { "util/handle/", handle_tests },
{ "util/logging/", logging_tests },
{ "util/process/", util_process_tests },
{ "util/thread/", thread_tests },
- { "util/handle/", handle_tests },
- { "dns/", dns_tests },
END_OF_GROUPS
};
diff --git a/src/test/test.h b/src/test/test.h
index aacc9dba87..56037648d3 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_H
@@ -37,6 +37,7 @@
#define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, OP_EQ, hex)
+#ifndef COCCI
#define tt_double_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,double,(val1_ op val2_),"%g", \
TT_EXIT_TEST_FUNCTION)
@@ -64,6 +65,7 @@
tt_assert_test_fmt_type(a,b,#a" "#op" "#b,int64_t,(val1_ op val2_), \
int64_t, "%"PRId64, \
{print_ = (int64_t) value_;}, {}, TT_EXIT_TEST_FUNCTION)
+#endif /* !defined(COCCI) */
/**
* Declare that the test is done, even though no tt___op() calls were made.
@@ -79,169 +81,101 @@ struct crypto_pk_t *pk_generate(int idx);
void init_pregenerated_keys(void);
void free_pregenerated_keys(void);
-#define US2_CONCAT_2__(a, b) a ## __ ## b
-#define US_CONCAT_2__(a, b) a ## _ ## b
-#define US_CONCAT_3__(a, b, c) a ## _ ## b ## _ ## c
-#define US_CONCAT_2_(a, b) US_CONCAT_2__(a, b)
-#define US_CONCAT_3_(a, b, c) US_CONCAT_3__(a, b, c)
-
-/*
- * These macros are helpful for streamlining the authorship of several test
- * cases that use mocks.
- *
- * The pattern is as follows.
- * * Declare a top level namespace:
- * #define NS_MODULE foo
- *
- * * For each test case you want to write, create a new submodule in the
- * namespace. All mocks and other information should belong to a single
- * submodule to avoid interference with other test cases.
- * You can simply name the submodule after the function in the module you
- * are testing:
- * #define NS_SUBMODULE some_function
- * or, if you're wanting to write several tests against the same function,
- * ie., you are testing an aspect of that function, you can use:
- * #define NS_SUBMODULE ASPECT(some_function, behavior)
- *
- * * Declare all the mocks you will use. The NS_DECL macro serves to declare
- * the mock in the current namespace (defined by NS_MODULE and NS_SUBMODULE).
- * It behaves like MOCK_DECL:
- * NS_DECL(int, dependent_function, (void *));
- * Here, dependent_function must be declared and implemented with the
- * MOCK_DECL and MOCK_IMPL macros. The NS_DECL macro also defines an integer
- * global for use for tracking how many times a mock was called, and can be
- * accessed by CALLED(mock_name). For example, you might put
- * CALLED(dependent_function)++;
- * in your mock body.
- *
- * * Define a function called NS(main) that will contain the body of the
- * test case. The NS macro can be used to reference a name in the current
- * namespace.
- *
- * * In NS(main), indicate that a mock function in the current namespace,
- * declared with NS_DECL is to override that in the global namespace,
- * with the NS_MOCK macro:
- * NS_MOCK(dependent_function)
- * Unmock with:
- * NS_UNMOCK(dependent_function)
- *
- * * Define the mocks with the NS macro, eg.,
- * int
- * NS(dependent_function)(void *)
- * {
- * CALLED(dependent_function)++;
- * }
- *
- * * In the struct testcase_t array, you can use the TEST_CASE and
- * TEST_CASE_ASPECT macros to define the cases without having to do so
- * explicitly nor without having to reset NS_SUBMODULE, eg.,
- * struct testcase_t foo_tests[] = {
- * TEST_CASE_ASPECT(some_function, behavior),
- * ...
- * END_OF_TESTCASES
- * which will define a test case named "some_function__behavior".
- */
-
-#define NAME_TEST_(name) #name
-#define NAME_TEST(name) NAME_TEST_(name)
-#define ASPECT(test_module, test_name) US2_CONCAT_2__(test_module, test_name)
-#define TEST_CASE(function) \
- { \
- NAME_TEST(function), \
- NS_FULL(NS_MODULE, function, test_main), \
- TT_FORK, \
- NULL, \
- NULL, \
- }
-#define TEST_CASE_ASPECT(function, aspect) \
- { \
- NAME_TEST(ASPECT(function, aspect)), \
- NS_FULL(NS_MODULE, ASPECT(function, aspect), test_main), \
- TT_FORK, \
- NULL, \
- NULL, \
- }
-
-#define NS(name) US_CONCAT_3_(NS_MODULE, NS_SUBMODULE, name)
-#define NS_FULL(module, submodule, name) US_CONCAT_3_(module, submodule, name)
-
-#define CALLED(mock_name) US_CONCAT_2_(NS(mock_name), called)
-#define NS_DECL(retval, mock_fn, args) \
- extern int CALLED(mock_fn); \
- static retval NS(mock_fn) args; int CALLED(mock_fn) = 0
-#define NS_MOCK(name) MOCK(name, NS(name))
-#define NS_UNMOCK(name) UNMOCK(name)
-
extern const struct testcase_setup_t passthrough_setup;
extern const struct testcase_setup_t ed25519_test_setup;
extern struct testcase_t accounting_tests[];
extern struct testcase_t addr_tests[];
-extern struct testcase_t address_tests[];
extern struct testcase_t address_set_tests[];
+extern struct testcase_t address_tests[];
extern struct testcase_t bridges_tests[];
-extern struct testcase_t bwmgt_tests[];
+extern struct testcase_t btrack_tests[];
extern struct testcase_t buffer_tests[];
+extern struct testcase_t bwmgt_tests[];
extern struct testcase_t cell_format_tests[];
extern struct testcase_t cell_queue_tests[];
extern struct testcase_t channel_tests[];
extern struct testcase_t channelpadding_tests[];
+extern struct testcase_t circuitpadding_tests[];
extern struct testcase_t channeltls_tests[];
extern struct testcase_t checkdir_tests[];
extern struct testcase_t circuitbuild_tests[];
extern struct testcase_t circuitlist_tests[];
extern struct testcase_t circuitmux_tests[];
-extern struct testcase_t circuituse_tests[];
+extern struct testcase_t circuitmux_ewma_tests[];
extern struct testcase_t circuitstats_tests[];
+extern struct testcase_t circuituse_tests[];
extern struct testcase_t compat_libevent_tests[];
extern struct testcase_t config_tests[];
+extern struct testcase_t confmgr_tests[];
+extern struct testcase_t confparse_tests[];
extern struct testcase_t connection_tests[];
extern struct testcase_t conscache_tests[];
extern struct testcase_t consdiff_tests[];
extern struct testcase_t consdiffmgr_tests[];
extern struct testcase_t container_tests[];
-extern struct testcase_t controller_tests[];
extern struct testcase_t controller_event_tests[];
-extern struct testcase_t crypto_tests[];
+extern struct testcase_t controller_tests[];
extern struct testcase_t crypto_ope_tests[];
extern struct testcase_t crypto_openssl_tests[];
-extern struct testcase_t dir_tests[];
+extern struct testcase_t crypto_rng_tests[];
+extern struct testcase_t crypto_tests[];
extern struct testcase_t dir_handle_get_tests[];
+extern struct testcase_t dir_tests[];
+extern struct testcase_t dirvote_tests[];
+extern struct testcase_t dispatch_tests[];
+extern struct testcase_t dns_tests[];
extern struct testcase_t dos_tests[];
extern struct testcase_t entryconn_tests[];
extern struct testcase_t entrynodes_tests[];
-extern struct testcase_t guardfraction_tests[];
extern struct testcase_t extorport_tests[];
extern struct testcase_t geoip_tests[];
-extern struct testcase_t hs_tests[];
+extern struct testcase_t guardfraction_tests[];
+extern struct testcase_t handle_tests[];
extern struct testcase_t hs_cache[];
extern struct testcase_t hs_cell_tests[];
+extern struct testcase_t hs_client_tests[];
extern struct testcase_t hs_common_tests[];
extern struct testcase_t hs_config_tests[];
extern struct testcase_t hs_control_tests[];
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_metrics_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_client_tests[];
-extern struct testcase_t hs_intropoint_tests[];
+extern struct testcase_t hs_tests[];
extern struct testcase_t introduce_tests[];
extern struct testcase_t keypin_tests[];
extern struct testcase_t link_handshake_tests[];
extern struct testcase_t logging_tests[];
extern struct testcase_t mainloop_tests[];
+extern struct testcase_t metrics_tests[];
extern struct testcase_t microdesc_tests[];
+extern struct testcase_t namemap_tests[];
+extern struct testcase_t netinfo_tests[];
extern struct testcase_t nodelist_tests[];
extern struct testcase_t oom_tests[];
extern struct testcase_t oos_tests[];
extern struct testcase_t options_tests[];
+extern struct testcase_t options_act_tests[];
+extern struct testcase_t parsecommon_tests[];
extern struct testcase_t pem_tests[];
extern struct testcase_t periodic_event_tests[];
extern struct testcase_t policy_tests[];
+extern struct testcase_t prob_distr_tests[];
+extern struct testcase_t slow_stochastic_prob_distr_tests[];
extern struct testcase_t procmon_tests[];
+extern struct testcase_t process_tests[];
+extern struct testcase_t process_descs_tests[];
+extern struct testcase_t proto_haproxy_tests[];
extern struct testcase_t proto_http_tests[];
extern struct testcase_t proto_misc_tests[];
extern struct testcase_t protover_tests[];
extern struct testcase_t pt_tests[];
+extern struct testcase_t pubsub_build_tests[];
+extern struct testcase_t pubsub_msg_tests[];
extern struct testcase_t relay_tests[];
extern struct testcase_t relaycell_tests[];
extern struct testcase_t relaycrypt_tests[];
@@ -252,23 +186,27 @@ extern struct testcase_t routerkeys_tests[];
extern struct testcase_t routerlist_tests[];
extern struct testcase_t routerset_tests[];
extern struct testcase_t scheduler_tests[];
-extern struct testcase_t storagedir_tests[];
+extern struct testcase_t sendme_tests[];
extern struct testcase_t socks_tests[];
+extern struct testcase_t sr_tests[];
+extern struct testcase_t statefile_tests[];
+extern struct testcase_t stats_tests[];
extern struct testcase_t status_tests[];
+extern struct testcase_t storagedir_tests[];
extern struct testcase_t thread_tests[];
-extern struct testcase_t tortls_tests[];
+extern struct testcase_t token_bucket_tests[];
extern struct testcase_t tortls_openssl_tests[];
-extern struct testcase_t util_tests[];
+extern struct testcase_t tortls_tests[];
extern struct testcase_t util_format_tests[];
extern struct testcase_t util_process_tests[];
+extern struct testcase_t util_tests[];
+extern struct testcase_t voting_flags_tests[];
extern struct testcase_t voting_schedule_tests[];
-extern struct testcase_t dns_tests[];
-extern struct testcase_t handle_tests[];
-extern struct testcase_t sr_tests[];
extern struct testcase_t x509_tests[];
extern struct testcase_t slow_crypto_tests[];
-extern struct testcase_t slow_util_tests[];
+extern struct testcase_t slow_process_tests[];
+extern struct testcase_t slow_ptr_tests[];
extern struct testgroup_t testgroups[];
diff --git a/src/test/test_accounting.c b/src/test/test_accounting.c
index 8ae8fe4343..7933df5e35 100644
--- a/src/test/test_accounting.c
+++ b/src/test/test_accounting.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -11,19 +11,16 @@
#include "app/config/or_state_st.h"
-#define NS_MODULE accounting
-
-#define NS_SUBMODULE limits
-
/*
* Test to make sure accounting triggers hibernation
* correctly with both sum or max rules set
*/
static or_state_t *or_state;
-NS_DECL(or_state_t *, get_or_state, (void));
+static or_state_t * acct_limits_get_or_state(void);
+ATTR_UNUSED static int acct_limits_get_or_state_called = 0;
static or_state_t *
-NS(get_or_state)(void)
+acct_limits_get_or_state(void)
{
return or_state;
}
@@ -35,7 +32,8 @@ test_accounting_limits(void *arg)
time_t fake_time = time(NULL);
(void) arg;
- NS_MOCK(get_or_state);
+ MOCK(get_or_state,
+ acct_limits_get_or_state);
or_state = or_state_new();
options->AccountingMax = 100;
@@ -94,12 +92,10 @@ test_accounting_limits(void *arg)
goto done;
done:
- NS_UNMOCK(get_or_state);
+ UNMOCK(get_or_state);
or_state_free(or_state);
}
-#undef NS_SUBMODULE
-
struct testcase_t accounting_tests[] = {
{ "bwlimits", test_accounting_limits, TT_FORK, NULL, NULL },
END_OF_TESTCASES
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 8868edce25..dbc581288d 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ADDRESSMAP_PRIVATE
@@ -11,6 +11,8 @@
#include "feature/client/addressmap.h"
#include "test/log_test_helpers.h"
#include "lib/net/resolve.h"
+#include "test/rng_test_helpers.h"
+#include "test/resolve_test_helpers.h"
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
@@ -50,6 +52,7 @@ test_addr_basic(void *arg)
;
}
+#ifndef COCCI
#define test_op_ip6_(a,op,b,e1,e2) \
STMT_BEGIN \
tt_assert_test_fmt_type(a,b,e1" "#op" "e2,struct in6_addr*, \
@@ -67,6 +70,7 @@ test_addr_basic(void *arg)
TT_EXIT_TEST_FUNCTION \
); \
STMT_END
+#endif /* !defined(COCCI) */
/** Helper: Assert that two strings both decode as IPv6 addresses with
* tor_inet_pton(), and both decode to the same address. */
@@ -106,9 +110,10 @@ test_addr_basic(void *arg)
tt_int_op(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), OP_EQ, 1); \
t1.family = AF_INET6; \
if (tor_addr_is_internal(&t1, for_listening)) \
- TT_DIE(("%s was not internal", a)); \
+ TT_DIE(("%s was internal", a)); \
STMT_END
+#ifndef COCCI
/** Helper: Assert that <b>a</b> and <b>b</b>, when parsed by
* tor_inet_pton(), give addresses that compare in the order defined by
* <b>op</b> with tor_addr_compare(). */
@@ -133,6 +138,7 @@ test_addr_basic(void *arg)
TT_DIE(("Failed: tor_addr_compare_masked(%s,%s,%d) %s 0", \
a, b, m, #op)); \
STMT_END
+#endif /* !defined(COCCI) */
/** Helper: assert that <b>xx</b> is parseable as a masked IPv6 address with
* ports by tor_parse_mask_addr_ports(), with family <b>f</b>, IP address
@@ -239,7 +245,7 @@ test_addr_ip6_helpers(void *arg)
tt_int_op(0,OP_EQ, tor_addr_lookup("9000::5", AF_UNSPEC, &t1));
tt_int_op(AF_INET6,OP_EQ, tor_addr_family(&t1));
tt_int_op(0x90,OP_EQ, tor_addr_to_in6_addr8(&t1)[0]);
- tt_assert(tor_mem_is_zero((char*)tor_addr_to_in6_addr8(&t1)+1, 14));
+ tt_assert(fast_mem_is_zero((char*)tor_addr_to_in6_addr8(&t1)+1, 14));
tt_int_op(0x05,OP_EQ, tor_addr_to_in6_addr8(&t1)[15]);
/* === Test pton: valid af_inet6 */
@@ -335,6 +341,7 @@ test_addr_ip6_helpers(void *arg)
test_pton6_bad("0XYXXY");
test_pton6_bad("0x");
test_pton6_bad("0X");
+ test_pton6_bad("2000::1a00::1000:fc098");
/* test internal checking */
test_external_ip("fbff:ffff::2:7", 0);
@@ -653,12 +660,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);
@@ -696,7 +698,7 @@ test_addr_ip6_helpers(void *arg)
&t1,&mask,&port1,&port2);
tt_int_op(r,OP_EQ,AF_INET6);
tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET6);
- tt_assert(tor_mem_is_zero((const char*)tor_addr_to_in6_addr32(&t1), 16));
+ tt_assert(fast_mem_is_zero((const char*)tor_addr_to_in6_addr32(&t1), 16));
tt_int_op(mask,OP_EQ,0);
tt_int_op(port1,OP_EQ,1);
tt_int_op(port2,OP_EQ,65535);
@@ -723,104 +725,559 @@ test_addr_ip6_helpers(void *arg)
;
}
-/** Test tor_addr_port_parse(). */
+/* Test that addr_str successfully parses, and:
+ * - the address has family expect_family,
+ * - the fmt_decorated result of tor_addr_to_str() is expect_str.
+ */
+#define TEST_ADDR_PARSE_FMT(addr_str, expect_family, fmt_decorated, \
+ expect_str) \
+ STMT_BEGIN \
+ r = tor_addr_parse(&addr, addr_str); \
+ tt_int_op(r, OP_EQ, expect_family); \
+ sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \
+ tt_str_op(sv, OP_EQ, buf); \
+ tt_str_op(buf, OP_EQ, expect_str); \
+ STMT_END
+
+/* Test that addr_str fails to parse, and:
+ * - the returned address is null.
+ */
+#define TEST_ADDR_PARSE_XFAIL(addr_str) \
+ STMT_BEGIN \
+ r = tor_addr_parse(&addr, addr_str); \
+ tt_int_op(r, OP_EQ, -1); \
+ tt_assert(tor_addr_is_null(&addr)); \
+ STMT_END
+
+/* Test that addr_port_str and default_port successfully parse, and:
+ * - the address has family expect_family,
+ * - the fmt_decorated result of tor_addr_to_str() is expect_str,
+ * - the port is expect_port.
+ */
+#define TEST_ADDR_PORT_PARSE_FMT(addr_port_str, default_port, expect_family, \
+ fmt_decorated, expect_str, expect_port) \
+ STMT_BEGIN \
+ r = tor_addr_port_parse(LOG_DEBUG, addr_port_str, &addr, &port, \
+ default_port); \
+ tt_int_op(r, OP_EQ, 0); \
+ tt_int_op(tor_addr_family(&addr), OP_EQ, expect_family); \
+ sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \
+ tt_str_op(sv, OP_EQ, buf); \
+ tt_str_op(buf, OP_EQ, expect_str); \
+ tt_int_op(port, OP_EQ, expect_port); \
+ STMT_END
+
+/* Test that addr_port_str and default_port fail to parse, and:
+ * - the returned address is null,
+ * - the returned port is 0.
+ */
+#define TEST_ADDR_PORT_PARSE_XFAIL(addr_port_str, default_port) \
+ STMT_BEGIN \
+ r = tor_addr_port_parse(LOG_DEBUG, addr_port_str, &addr, &port, \
+ default_port); \
+ tt_int_op(r, OP_EQ, -1); \
+ tt_assert(tor_addr_is_null(&addr)); \
+ tt_int_op(port, OP_EQ, 0); \
+ STMT_END
+
+/* Test that addr_str successfully parses as an IPv4 address using
+ * tor_lookup_hostname(), and:
+ * - the fmt_addr32() of the result is expect_str.
+ */
+#define TEST_ADDR_V4_LOOKUP_HOSTNAME(addr_str, expect_str) \
+ STMT_BEGIN \
+ r = tor_lookup_hostname(addr_str, &addr32h); \
+ tt_int_op(r, OP_EQ, 0); \
+ tt_str_op(fmt_addr32(addr32h), OP_EQ, expect_str); \
+ STMT_END
+
+/* Test that bad_str fails to parse using tor_lookup_hostname(), with a
+ * permanent failure, and:
+ * - the returned address is 0.
+ */
+#define TEST_ADDR_V4_LOOKUP_XFAIL(bad_str) \
+ STMT_BEGIN \
+ r = tor_lookup_hostname(bad_str, &addr32h); \
+ tt_int_op(r, OP_EQ, -1); \
+ tt_int_op(addr32h, OP_EQ, 0); \
+ STMT_END
+
+/* Test that looking up host_str as an IPv4 address using tor_lookup_hostname()
+ * does something sensible:
+ * - the result is -1, 0, or 1.
+ * - if the result is a failure, the returned address is 0.
+ * We can't rely on the result of this function, because it depends on the
+ * network.
+ */
+#define TEST_HOST_V4_LOOKUP(host_str) \
+ STMT_BEGIN \
+ r = tor_lookup_hostname(host_str, &addr32h); \
+ tt_int_op(r, OP_GE, -1); \
+ tt_int_op(r, OP_LE, 1); \
+ if (r != 0) \
+ tt_int_op(addr32h, OP_EQ, 0); \
+ STMT_END
+
+/* Test that addr_str successfully parses as a require_family IP address using
+ * tor_addr_lookup(), and:
+ * - the address has family expect_family,
+ * - the fmt_decorated result of tor_addr_to_str() is expect_str.
+ */
+#define TEST_ADDR_LOOKUP_FMT(addr_str, require_family, expect_family, \
+ fmt_decorated, expect_str) \
+ STMT_BEGIN \
+ r = tor_addr_lookup(addr_str, require_family, &addr); \
+ tt_int_op(r, OP_EQ, 0); \
+ tt_int_op(tor_addr_family(&addr), OP_EQ, expect_family); \
+ sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \
+ tt_str_op(sv, OP_EQ, buf); \
+ tt_str_op(buf, OP_EQ, expect_str); \
+ STMT_END
+
+/* Test that bad_str fails to parse as a require_family IP address using
+ * tor_addr_lookup(), with a permanent failure, and:
+ * - the returned address is null.
+ */
+#define TEST_ADDR_LOOKUP_XFAIL(bad_str, require_family) \
+ STMT_BEGIN \
+ r = tor_addr_lookup(bad_str, require_family, &addr); \
+ tt_int_op(r, OP_EQ, -1); \
+ tt_assert(tor_addr_is_null(&addr)); \
+ STMT_END
+
+/* Test that looking up host_string as a require_family IP address using
+ * tor_addr_lookup(), does something sensible:
+ * - the result is -1, 0, or 1.
+ * - if the result is a failure, the returned address is null.
+ * We can't rely on the result of this function, because it depends on the
+ * network.
+ */
+#define TEST_HOST_LOOKUP(host_str, require_family) \
+ STMT_BEGIN \
+ r = tor_addr_lookup(host_str, require_family, &addr); \
+ tt_int_op(r, OP_GE, -1); \
+ tt_int_op(r, OP_LE, 1); \
+ if (r != 0) \
+ tt_assert(tor_addr_is_null(&addr)); \
+ STMT_END
+
+/* Test that addr_port_str successfully parses as an IP address and port
+ * using tor_addr_port_lookup(), and:
+ * - the address has family expect_family,
+ * - the fmt_decorated result of tor_addr_to_str() is expect_str,
+ * - the port is expect_port.
+ */
+#define TEST_ADDR_PORT_LOOKUP_FMT(addr_port_str, expect_family, \
+ fmt_decorated, expect_str, expect_port) \
+ STMT_BEGIN \
+ r = tor_addr_port_lookup(addr_port_str, &addr, &port); \
+ tt_int_op(r, OP_EQ, 0); \
+ tt_int_op(tor_addr_family(&addr), OP_EQ, expect_family); \
+ sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \
+ tt_str_op(sv, OP_EQ, buf); \
+ tt_str_op(buf, OP_EQ, expect_str); \
+ tt_int_op(port, OP_EQ, expect_port); \
+ STMT_END
+
+/* Test that bad_str fails to parse as an IP address and port
+ * using tor_addr_port_lookup(), and:
+ * - the returned address is null,
+ * - the returned port is 0.
+ */
+#define TEST_ADDR_PORT_LOOKUP_XFAIL(bad_str) \
+ STMT_BEGIN \
+ r = tor_addr_port_lookup(bad_str, &addr, &port); \
+ tt_int_op(r, OP_EQ, -1); \
+ tt_assert(tor_addr_is_null(&addr)); \
+ tt_int_op(port, OP_EQ, 0); \
+ STMT_END
+
+/* Test that looking up host_port_str as an IP address using
+ * tor_addr_port_lookup(), does something sensible:
+ * - the result is -1 or 0.
+ * - if the result is a failure, the returned address is null, and the
+ * returned port is zero,
+ * - if the result is a success, the returned port is expect_success_port,
+ * and the returned family is AF_INET or AF_INET6.
+ * We can't rely on the result of this function, because it depends on the
+ * network.
+ */
+#define TEST_HOST_PORT_LOOKUP(host_port_str, expect_success_port) \
+ STMT_BEGIN \
+ r = tor_addr_port_lookup(host_port_str, &addr, &port); \
+ tt_int_op(r, OP_GE, -1); \
+ tt_int_op(r, OP_LE, 0); \
+ if (r == -1) { \
+ tt_assert(tor_addr_is_null(&addr)); \
+ tt_int_op(port, OP_EQ, 0); \
+ } else { \
+ tt_assert(tor_addr_family(&addr) == AF_INET || \
+ tor_addr_family(&addr) == AF_INET6); \
+ tt_int_op(port, OP_EQ, expect_success_port); \
+ } \
+ STMT_END
+
+/* Test that addr_str successfully parses as a canonical IPv4 address.
+ * Check for successful parsing using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() with a default port,
+ * - tor_lookup_hostname(),
+ * - tor_addr_lookup() with AF_INET,
+ * - tor_addr_lookup() with AF_UNSPEC,
+ * - tor_addr_port_lookup(), with a zero port.
+ * Check for failures using:
+ * - tor_addr_port_parse() without a default port, because there is no port,
+ * - tor_addr_lookup() with AF_INET6,
+ * - tor_addr_port_lookup(), because there is no port.
+ */
+#define TEST_ADDR_V4_PARSE_CANONICAL(addr_str) \
+ STMT_BEGIN \
+ TEST_ADDR_PARSE_FMT(addr_str, AF_INET, 0, addr_str); \
+ TEST_ADDR_PORT_PARSE_FMT(addr_str, 111, AF_INET, 0, \
+ addr_str, 111); \
+ TEST_ADDR_V4_LOOKUP_HOSTNAME(addr_str, addr_str); \
+ TEST_ADDR_PORT_LOOKUP_FMT(addr_str, AF_INET, 0, addr_str, 0); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_INET, AF_INET, 0, addr_str); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET, 0, addr_str); \
+ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET6); \
+ STMT_END
+
+/* Test that addr_str successfully parses as a canonical fmt_decorated
+ * IPv6 address.
+ * Check for successful parsing using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() with a default port,
+ * - tor_addr_lookup() with AF_INET6,
+ * - tor_addr_lookup() with AF_UNSPEC,
+ * - tor_addr_port_lookup(), with a zero port.
+ * Check for failures using:
+ * - tor_addr_port_parse() without a default port, because there is no port,
+ * - tor_lookup_hostname(), because it only supports IPv4,
+ * - tor_addr_lookup() with AF_INET.
+ */
+#define TEST_ADDR_V6_PARSE_CANONICAL(addr_str, fmt_decorated) \
+ STMT_BEGIN \
+ TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, addr_str); \
+ TEST_ADDR_PORT_PARSE_FMT(addr_str, 222, AF_INET6, fmt_decorated, \
+ addr_str, 222); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_INET6, AF_INET6, fmt_decorated, \
+ addr_str); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET6, fmt_decorated, \
+ addr_str); \
+ TEST_ADDR_PORT_LOOKUP_FMT(addr_str, AF_INET6, fmt_decorated, addr_str, \
+ 0); \
+ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET); \
+ STMT_END
+
+/* Test that addr_str successfully parses, and the fmt_decorated canonical
+ * IPv6 string is expect_str.
+ * Check for successful parsing using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() with a default port,
+ * - tor_addr_lookup() with AF_INET6,
+ * - tor_addr_lookup() with AF_UNSPEC,
+ * - tor_addr_port_lookup(), with a zero port.
+ * Check for failures using:
+ * - tor_addr_port_parse() without a default port, because there is no port.
+ * - tor_lookup_hostname(), because it only supports IPv4,
+ * - tor_addr_lookup() with AF_INET.
+ */
+#define TEST_ADDR_V6_PARSE(addr_str, fmt_decorated, expect_str) \
+ STMT_BEGIN \
+ TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, expect_str); \
+ TEST_ADDR_PORT_PARSE_FMT(addr_str, 333, AF_INET6, fmt_decorated, \
+ expect_str, 333); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_INET6, AF_INET6, fmt_decorated, \
+ expect_str); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET6, fmt_decorated, \
+ expect_str); \
+ TEST_ADDR_PORT_LOOKUP_FMT(addr_str, AF_INET6, fmt_decorated, expect_str, \
+ 0); \
+ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET); \
+ STMT_END
+
+/* Test that addr_port_str successfully parses to the canonical IPv4 address
+ * string expect_str, and port expect_port.
+ * Check for successful parsing using:
+ * - tor_addr_port_parse() without a default port,
+ * - tor_addr_port_parse() with a default port,
+ * - tor_addr_port_lookup().
+ * Check for failures using:
+ * - tor_addr_parse(), because there is a port,
+ * - tor_lookup_hostname(), because there is a port.
+ * - tor_addr_lookup(), regardless of the address family, because there is a
+ * port.
+ */
+#define TEST_ADDR_V4_PORT_PARSE(addr_port_str, expect_str, expect_port) \
+ STMT_BEGIN \
+ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, 444, AF_INET, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PORT_LOOKUP_FMT(addr_port_str, AF_INET, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PARSE_XFAIL(addr_port_str); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(addr_port_str); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_UNSPEC); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET6); \
+ STMT_END
+
+/* Test that addr_port_str successfully parses to the canonical undecorated
+ * IPv6 address string expect_str, and port expect_port.
+ * Check for successful parsing using:
+ * - tor_addr_port_parse() without a default port,
+ * - tor_addr_port_parse() with a default port,
+ * - tor_addr_port_lookup().
+ * Check for failures using:
+ * - tor_addr_parse(), because there is a port,
+ * - tor_lookup_hostname(), because there is a port, and because it only
+ * supports IPv4,
+ * - tor_addr_lookup(), regardless of the address family, because there is a
+ * port.
+ */
+#define TEST_ADDR_V6_PORT_PARSE(addr_port_str, expect_str, expect_port) \
+ STMT_BEGIN \
+ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET6, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, 555, AF_INET6, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PORT_LOOKUP_FMT(addr_port_str, AF_INET6, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PARSE_XFAIL(addr_port_str); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(addr_port_str); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET6); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_UNSPEC); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET); \
+ STMT_END
+
+/* Test that bad_str fails to parse due to a bad address or port.
+ * Check for failures using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() without a default port,
+ * - tor_addr_port_parse() with a default port,
+ * - tor_lookup_hostname(),
+ * - tor_addr_lookup(), regardless of the address family,
+ * - tor_addr_port_lookup().
+ */
+#define TEST_ADDR_PARSE_XFAIL_MALFORMED(bad_str) \
+ STMT_BEGIN \
+ TEST_ADDR_PARSE_XFAIL(bad_str); \
+ TEST_ADDR_PORT_PARSE_XFAIL(bad_str, -1); \
+ TEST_ADDR_PORT_PARSE_XFAIL(bad_str, 666); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(bad_str); \
+ TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_UNSPEC); \
+ TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_INET); \
+ TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_INET6); \
+ TEST_ADDR_PORT_LOOKUP_XFAIL(bad_str); \
+ STMT_END
+
+/* Test that host_str is treated as a hostname, and not an address.
+ * Check for success or failure using the network-dependent functions:
+ * - tor_lookup_hostname(),
+ * - tor_addr_lookup(), regardless of the address family,
+ * - tor_addr_port_lookup(), expecting a zero port.
+ * Check for failures using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() without a default port,
+ * - tor_addr_port_parse() with a default port.
+ */
+#define TEST_HOSTNAME(host_str) \
+ STMT_BEGIN \
+ TEST_HOST_V4_LOOKUP(host_str); \
+ TEST_HOST_LOOKUP(host_str, AF_UNSPEC); \
+ TEST_HOST_LOOKUP(host_str, AF_INET); \
+ TEST_HOST_LOOKUP(host_str, AF_INET6); \
+ TEST_HOST_PORT_LOOKUP(host_str, 0); \
+ TEST_ADDR_PARSE_XFAIL(host_str); \
+ TEST_ADDR_PORT_PARSE_XFAIL(host_str, -1); \
+ TEST_ADDR_PORT_PARSE_XFAIL(host_str, 777); \
+ STMT_END
+
+/* Test that host_port_str is treated as a hostname and port, and not a
+ * hostname or an address.
+ * Check for success or failure using the network-dependent function:
+ * - tor_addr_port_lookup(), expecting expect_success_port if the lookup is
+ * successful.
+ * Check for failures using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() without a default port,
+ * - tor_addr_port_parse() with a default port,
+ * - tor_lookup_hostname(), because it doesn't support ports,
+ * - tor_addr_lookup(), regardless of the address family, because it doesn't
+ * support ports.
+ */
+#define TEST_HOSTNAME_PORT(host_port_str, expect_success_port) \
+ STMT_BEGIN \
+ TEST_HOST_PORT_LOOKUP(host_port_str, expect_success_port); \
+ TEST_ADDR_PARSE_XFAIL(host_port_str); \
+ TEST_ADDR_PORT_PARSE_XFAIL(host_port_str, -1); \
+ TEST_ADDR_PORT_PARSE_XFAIL(host_port_str, 888); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(host_port_str); \
+ TEST_ADDR_LOOKUP_XFAIL(host_port_str, AF_UNSPEC); \
+ TEST_ADDR_LOOKUP_XFAIL(host_port_str, AF_INET); \
+ TEST_ADDR_LOOKUP_XFAIL(host_port_str, AF_INET6); \
+ STMT_END
+
+static void
+test_addr_parse_canonical(void *arg)
+{
+ int r;
+ tor_addr_t addr;
+ uint16_t port;
+ const char *sv;
+ uint32_t addr32h;
+ char buf[TOR_ADDR_BUF_LEN];
+
+ (void)arg;
+
+ /* Correct calls. */
+ TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.1");
+ TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.2");
+
+ TEST_ADDR_V6_PARSE_CANONICAL("[11:22::33:44]", 1);
+ TEST_ADDR_V6_PARSE_CANONICAL("[::1]", 1);
+ TEST_ADDR_V6_PARSE_CANONICAL("[::]", 1);
+ TEST_ADDR_V6_PARSE_CANONICAL("[2::]", 1);
+ TEST_ADDR_V6_PARSE_CANONICAL("[11:22:33:44:55:66:77:88]", 1);
+
+ /* Allow IPv6 without square brackets, when there is no port, but only if
+ * there is a default port */
+ TEST_ADDR_V6_PARSE_CANONICAL("11:22::33:44", 0);
+ TEST_ADDR_V6_PARSE_CANONICAL("::1", 0);
+ TEST_ADDR_V6_PARSE_CANONICAL("::", 0);
+ TEST_ADDR_V6_PARSE_CANONICAL("2::", 0);
+ TEST_ADDR_V6_PARSE_CANONICAL("11:22:33:44:55:66:77:88", 0);
+ done:
+ ;
+}
+
+/** Test tor_addr_parse() and tor_addr_port_parse(). */
static void
test_addr_parse(void *arg)
{
+
int r;
tor_addr_t addr;
+ uint16_t port;
+ const char *sv;
+ uint32_t addr32h;
char buf[TOR_ADDR_BUF_LEN];
- uint16_t port = 0;
- /* Correct call. */
(void)arg;
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.1:1234",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, 0);
- tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- tt_str_op(buf,OP_EQ, "192.0.2.1");
- tt_int_op(port,OP_EQ, 1234);
-
- r= tor_addr_port_parse(LOG_DEBUG,
- "[::1]:1234",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, 0);
- tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- tt_str_op(buf,OP_EQ, "::1");
- tt_int_op(port,OP_EQ, 1234);
-
- /* Domain name. */
- r= tor_addr_port_parse(LOG_DEBUG,
- "torproject.org:1234",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
- /* Only IP. */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ mock_hostname_resolver();
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2",
- &addr, &port, 200);
- tt_int_op(r, OP_EQ, 0);
- tt_int_op(port,OP_EQ,200);
+ /* IPv6-mapped IPv4 addresses. Tor doesn't really use these. */
+ TEST_ADDR_V6_PARSE("11:22:33:44:55:66:1.2.3.4", 0,
+ "11:22:33:44:55:66:102:304");
- r= tor_addr_port_parse(LOG_DEBUG,
- "[::1]",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ TEST_ADDR_V6_PARSE("11:22::33:44:1.2.3.4", 0,
+ "11:22::33:44:102:304");
- r= tor_addr_port_parse(LOG_DEBUG,
- "[::1]",
- &addr, &port, 400);
- tt_int_op(r, OP_EQ, 0);
- tt_int_op(port,OP_EQ,400);
+ /* Ports. */
+ TEST_ADDR_V4_PORT_PARSE("192.0.2.1:1234", "192.0.2.1", 1234);
+ TEST_ADDR_V6_PORT_PARSE("[::1]:1234", "::1", 1234);
- /* Bad port. */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2:66666",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2:66666",
- &addr, &port, 200);
- tt_int_op(r, OP_EQ, -1);
+ /* Host names. */
+ TEST_HOSTNAME("localhost");
+ TEST_HOSTNAME_PORT("localhost:1234", 1234);
+ TEST_HOSTNAME_PORT("localhost:0", 0);
- /* Only domain name */
- r= tor_addr_port_parse(LOG_DEBUG,
- "torproject.org",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
- r= tor_addr_port_parse(LOG_DEBUG,
- "torproject.org",
- &addr, &port, 200);
- tt_int_op(r, OP_EQ, -1);
+ TEST_HOSTNAME("torproject.org");
+ TEST_HOSTNAME_PORT("torproject.org:56", 56);
- /* Bad IP address */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2:1234",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ TEST_HOSTNAME("probably-not-a-valid-dns.name-tld");
+ TEST_HOSTNAME_PORT("probably-not-a-valid-dns.name-tld:789", 789);
+
+ /* Malformed addresses. */
+ /* Empty string. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("");
+
+ /* Square brackets around IPv4 address. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[192.0.2.1]");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[192.0.2.3]:12345");
+
+ /* Only left square bracket. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[11:22::33:44");
+
+ /* Only right square bracket. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44]");
- /* Make sure that the default port has lower priority than the real
- one */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2:1337",
- &addr, &port, 200);
- tt_int_op(r, OP_EQ, 0);
- tt_int_op(port,OP_EQ,1337);
+ /* Leading colon. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED(":11:22::33:44");
- r= tor_addr_port_parse(LOG_DEBUG,
- "[::1]:1369",
- &addr, &port, 200);
- tt_int_op(r, OP_EQ, 0);
- tt_int_op(port,OP_EQ,1369);
+ /* Trailing colon. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:");
+
+ /* Bad port. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:66666");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:77777");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:88888");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:99999");
+
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:-1");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:-2");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:-3");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:-4");
+
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:1 bad");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:bad-port");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:bad-port-1");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:1-bad-port");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:1-bad-port");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:1-bad-port-1");
+
+ /* Bad hostname */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("definitely invalid");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("definitely invalid:22222");
+
+ /* Ambiguous cases */
+ /* Too many hex words in IPv4-mapped IPv6 address.
+ * But some OS host lookup routines accept it as a hostname, or
+ * as an IP address?? (I assume they discard unused characters). */
+ TEST_HOSTNAME("11:22:33:44:55:66:77:88:1.2.3.4");
+
+ /* IPv6 address with port and no brackets
+ * We reject it, but some OS host lookup routines accept it as an
+ * IPv6 address:port ? */
+ TEST_HOSTNAME_PORT("11:22::33:44:12345", 12345);
+ /* Is it a port, or are there too many hex words?
+ * We reject it either way, but some OS host lookup routines accept it as an
+ * IPv6 address:port */
+ TEST_HOSTNAME_PORT("11:22:33:44:55:66:77:88:99", 99);
+ /* But we accept it if it has square brackets. */
+ TEST_ADDR_V6_PORT_PARSE("[11:22:33:44:55:66:77:88]:99",
+ "11:22:33:44:55:66:77:88",99);
+
+ /* Bad IPv4 address
+ * We reject it, but some OS host lookup routines accept it as an
+ * IPv4 address[:port], with a zero last octet */
+ TEST_HOSTNAME("192.0.1");
+ TEST_HOSTNAME_PORT("192.0.2:1234", 1234);
+
+ /* More bad IPv6 addresses and ports: no brackets
+ * We reject it, but some OS host lookup routines accept it as an
+ * IPv6 address[:port] */
+ TEST_HOSTNAME_PORT("::1:12345", 12345);
+ TEST_HOSTNAME_PORT("11:22::33:44:12345", 12345);
+
+ /* And this is an ambiguous case, which is interpreted as an IPv6 address. */
+ TEST_ADDR_V6_PARSE_CANONICAL("11:22::88:99", 0);
+ /* Use square brackets to resolve the ambiguity */
+ TEST_ADDR_V6_PARSE_CANONICAL("[11:22::88:99]", 1);
+ TEST_ADDR_V6_PORT_PARSE("[11:22::88]:99",
+ "11:22::88",99);
done:
- ;
+ unmock_hostname_resolver();
}
static void
@@ -891,27 +1348,6 @@ test_virtaddrmap(void *data)
;
}
-static const char *canned_data = NULL;
-static size_t canned_data_len = 0;
-
-/* Mock replacement for crypto_rand() that returns canned data from
- * canned_data above. */
-static void
-crypto_canned(char *ptr, size_t n)
-{
- if (canned_data_len) {
- size_t to_copy = MIN(n, canned_data_len);
- memcpy(ptr, canned_data, to_copy);
- canned_data += to_copy;
- canned_data_len -= to_copy;
- n -= to_copy;
- ptr += to_copy;
- }
- if (n) {
- crypto_rand_unmocked(ptr, n);
- }
-}
-
static void
test_virtaddrmap_persist(void *data)
{
@@ -919,6 +1355,8 @@ test_virtaddrmap_persist(void *data)
const char *a, *b, *c;
tor_addr_t addr;
char *ones = NULL;
+ const char *canned_data;
+ size_t canned_data_len;
addressmap_init();
@@ -937,7 +1375,7 @@ test_virtaddrmap_persist(void *data)
"1234567890" // the second call returns this.
"abcdefghij"; // the third call returns this.
canned_data_len = 30;
- MOCK(crypto_rand, crypto_canned);
+ testing_enable_prefilled_rng(canned_data, canned_data_len);
a = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
tor_strdup("quuxit.baz"));
@@ -947,9 +1385,9 @@ test_virtaddrmap_persist(void *data)
tt_assert(b);
tt_str_op(a, OP_EQ, "gezdgnbvgy3tqojq.virtual");
tt_str_op(b, OP_EQ, "mfrggzdfmztwq2lk.virtual");
+ testing_disable_prefilled_rng();
// Now try something to get us an ipv4 address
- UNMOCK(crypto_rand);
tt_int_op(0,OP_EQ, parse_virtual_addr_network("192.168.0.0/16",
AF_INET, 0, NULL));
a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
@@ -966,22 +1404,23 @@ test_virtaddrmap_persist(void *data)
// Try some canned entropy and verify all the we discard duplicates,
// addresses that end with 0, and addresses that end with 255.
- MOCK(crypto_rand, crypto_canned);
canned_data = "\x01\x02\x03\x04" // okay
"\x01\x02\x03\x04" // duplicate
"\x03\x04\x00\x00" // bad ending 1
"\x05\x05\x00\xff" // bad ending 2
"\x05\x06\x07\xf0"; // okay
canned_data_len = 20;
+ testing_enable_prefilled_rng(canned_data, canned_data_len);
+
a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
tor_strdup("wumble.onion"));
b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
tor_strdup("wumpus.onion"));
tt_str_op(a, OP_EQ, "192.168.3.4");
tt_str_op(b, OP_EQ, "192.168.7.240");
+ testing_disable_prefilled_rng();
// Now try IPv6!
- UNMOCK(crypto_rand);
tt_int_op(0,OP_EQ, parse_virtual_addr_network("1010:F000::/20",
AF_INET6, 0, NULL));
a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
@@ -997,7 +1436,7 @@ test_virtaddrmap_persist(void *data)
tt_assert(!strcmpstart(b, "[1010:f"));
// Try IPv6 with canned entropy, to make sure we detect duplicates.
- MOCK(crypto_rand, crypto_canned);
+
canned_data = "acanthopterygian" // okay
"cinematographist" // okay
"acanthopterygian" // duplicate
@@ -1006,6 +1445,8 @@ test_virtaddrmap_persist(void *data)
"cinematographist" // duplicate
"coadministration"; // okay
canned_data_len = 16 * 7;
+ testing_enable_prefilled_rng(canned_data, canned_data_len);
+
a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
tor_strdup("wuffle.baz"));
b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
@@ -1018,9 +1459,11 @@ test_virtaddrmap_persist(void *data)
// Try address exhaustion: make sure we can actually fail if we
// get too many already-existing addresses.
+ testing_disable_prefilled_rng();
canned_data_len = 128*1024;
canned_data = ones = tor_malloc(canned_data_len);
memset(ones, 1, canned_data_len);
+ testing_enable_prefilled_rng(canned_data, canned_data_len);
// There is some chance this one will fail if a previous random
// allocation gave out the address already.
a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
@@ -1037,7 +1480,7 @@ test_virtaddrmap_persist(void *data)
expect_single_log_msg_containing("Ran out of virtual addresses!");
done:
- UNMOCK(crypto_rand);
+ testing_disable_prefilled_rng();
tor_free(ones);
addressmap_free_all();
teardown_capture_of_logs();
@@ -1206,13 +1649,169 @@ 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 }
+#endif
struct testcase_t addr_tests[] = {
ADDR_LEGACY(basic),
ADDR_LEGACY(ip6_helpers),
ADDR_LEGACY(parse),
+ ADDR_LEGACY(parse_canonical),
{ "virtaddr", test_virtaddrmap, 0, NULL, NULL },
{ "virtaddr_persist", test_virtaddrmap_persist, TT_FORK, NULL, NULL },
{ "localname", test_addr_localname, 0, NULL, NULL },
@@ -1221,5 +1820,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 c33c30aee5..e7007f22f3 100644
--- a/src/test/test_address.c
+++ b/src/test/test_address.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ADDRESS_PRIVATE
@@ -24,6 +24,10 @@
#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */
#include "core/or/or.h"
+#include "app/config/config.h"
+#include "feature/dirauth/process_descs.h"
+#include "feature/nodelist/routerinfo_st.h"
+#include "feature/nodelist/node_st.h"
#include "feature/nodelist/nodelist.h"
#include "lib/net/address.h"
#include "test/test.h"
@@ -456,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);
@@ -479,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);
@@ -709,7 +713,7 @@ test_address_udp_socket_trick_blackbox(void *arg)
#else /* !(0) */
/* Both of the blackbox test cases fail horribly if:
- * * The host has no external addreses.
+ * * The host has no external addresses.
* * There are multiple interfaces with either AF_INET or AF_INET6.
* * The last address isn't the one associated with the default route.
*
@@ -1148,30 +1152,185 @@ test_address_tor_addr_in_same_network_family(void *ignored)
tor_addr_parse(&a, "8.8.8.8");
tor_addr_parse(&b, "8.8.4.4");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 1);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 1);
tor_addr_parse(&a, "8.8.8.8");
tor_addr_parse(&b, "1.1.1.1");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 0);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 0);
tor_addr_parse(&a, "8.8.8.8");
tor_addr_parse(&b, "2001:4860:4860::8844");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 0);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 0);
tor_addr_parse(&a, "2001:4860:4860::8888");
tor_addr_parse(&b, "2001:4860:4860::8844");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 1);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 1);
tor_addr_parse(&a, "2001:4860:4860::8888");
tor_addr_parse(&b, "2001:470:20::2");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 0);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 0);
done:
return;
}
+static node_t *
+helper_create_mock_node(char id_char)
+{
+ node_t *node = tor_malloc_zero(sizeof(node_t));
+ routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t));
+ tor_addr_make_null(&ri->ipv6_addr, AF_INET6);
+ node->ri = ri;
+ memset(node->identity, id_char, sizeof(node->identity));
+ return node;
+}
+
+static void
+helper_free_mock_node(node_t *node)
+{
+ if (!node)
+ return;
+ tor_free(node->ri);
+ tor_free(node);
+}
+
+#define NODE_SET_IPV4(node, ipv4_addr_str, ipv4_port) { \
+ tor_addr_parse(&(node)->ri->ipv4_addr, ipv4_addr_str); \
+ node->ri->ipv4_orport = ipv4_port; \
+ }
+
+#define NODE_CLEAR_IPV4(node) { \
+ tor_addr_make_unspec(&node->ri->ipv4_addr); \
+ node->ri->ipv4_orport = 0; \
+ }
+
+#define NODE_SET_IPV6(node, ipv6_addr_str, ipv6_port) { \
+ tor_addr_parse(&node->ri->ipv6_addr, ipv6_addr_str); \
+ node->ri->ipv6_orport = ipv6_port; \
+ }
+
+static void
+test_address_tor_node_in_same_network_family(void *ignored)
+{
+ (void)ignored;
+ node_t *node_a = helper_create_mock_node('a');
+ node_t *node_b = helper_create_mock_node('b');
+
+ NODE_SET_IPV4(node_a, "8.8.8.8", 1);
+ NODE_SET_IPV4(node_b, "8.8.4.4", 1);
+
+ tt_int_op(nodes_in_same_family(node_a, node_b), OP_EQ, 1);
+
+ NODE_SET_IPV4(node_a, "8.8.8.8", 1);
+ NODE_SET_IPV4(node_b, "1.1.1.1", 1);
+
+ tt_int_op(nodes_in_same_family(node_a, node_b), OP_EQ, 0);
+
+ NODE_CLEAR_IPV4(node_a);
+ NODE_SET_IPV6(node_a, "2001:470:20::2", 1);
+
+ tt_int_op(nodes_in_same_family(node_a, node_b), OP_EQ, 0);
+
+ NODE_CLEAR_IPV4(node_b);
+ NODE_SET_IPV6(node_b, "2606:4700:4700::1111", 1);
+
+ tt_int_op(nodes_in_same_family(node_a, node_b), OP_EQ, 0);
+
+ NODE_SET_IPV6(node_a, "2606:4700:4700::1001", 1);
+ tt_int_op(nodes_in_same_family(node_a, node_b), OP_EQ, 1);
+
+ done:
+ helper_free_mock_node(node_a);
+ helper_free_mock_node(node_b);
+}
+
+static or_options_t mock_options;
+
+static const or_options_t *
+mock_get_options(void)
+{
+ return &mock_options;
+}
+
+/* Test dirserv_router_has_valid_address() on a stub routerinfo, with only its
+ * address fields set. Use IPv4 ipv4_addr_str and IPv6 ipv6_addr_str.
+ * Fail if it does not return rv. */
+#define TEST_ROUTER_VALID_ADDRESS_HELPER(ipv4_addr_str, ipv6_addr_str, rv) \
+ STMT_BEGIN \
+ ri = tor_malloc_zero(sizeof(routerinfo_t)); \
+ tor_addr_parse(&ri->ipv4_addr, (ipv4_addr_str)); \
+ tor_addr_parse(&ri->ipv6_addr, (ipv6_addr_str)); \
+ tt_int_op(dirserv_router_has_valid_address(ri), OP_EQ, (rv)); \
+ tor_free(ri); \
+ STMT_END
+
+/* Like TEST_ROUTER_VALID_ADDRESS_HELPER(), but always passes a null
+ * IPv6 address. */
+#define CHECK_RI_ADDR(ipv4_addr_str, rv) \
+ TEST_ROUTER_VALID_ADDRESS_HELPER(ipv4_addr_str, "::", rv)
+
+/* Like TEST_ROUTER_VALID_ADDRESS_HELPER(), but always passes a non-internal
+ * IPv4 address, so that the IPv6 check is reached. */
+#define CHECK_RI_ADDR6(ipv6_addr_str, rv) \
+ TEST_ROUTER_VALID_ADDRESS_HELPER("1.0.0.1", ipv6_addr_str, rv)
+
+static void
+test_address_dirserv_router_addr_private(void *opt_dir_allow_private)
+{
+ /* A stub routerinfo structure, with only its address fields set. */
+ routerinfo_t *ri = NULL;
+ /* The expected return value for private addresses.
+ * Modified if DirAllowPrivateAddresses is 1. */
+ int private_rv = -1;
+
+ memset(&mock_options, 0, sizeof(or_options_t));
+ MOCK(get_options, mock_get_options);
+
+ if (opt_dir_allow_private) {
+ mock_options.DirAllowPrivateAddresses = 1;
+ private_rv = 0;
+ }
+
+ CHECK_RI_ADDR("1.0.0.1", 0);
+ CHECK_RI_ADDR("10.0.0.1", private_rv);
+
+ CHECK_RI_ADDR6("2600::1", 0);
+ CHECK_RI_ADDR6("fe80::1", private_rv);
+
+ /* Null addresses */
+ /* IPv4 null fails, regardless of IPv6 */
+ CHECK_RI_ADDR("0.0.0.0", private_rv);
+ TEST_ROUTER_VALID_ADDRESS_HELPER("0.0.0.0", "::", private_rv);
+
+ /* IPv6 null succeeds, because IPv4 is not null */
+ CHECK_RI_ADDR6("::", 0);
+
+ /* Byte-zeroed null addresses */
+ /* IPv4 null fails, regardless of IPv6 */
+ {
+ ri = tor_malloc_zero(sizeof(routerinfo_t));
+ tt_int_op(dirserv_router_has_valid_address(ri), OP_EQ, private_rv);
+ tor_free(ri);
+ }
+
+ /* IPv6 null succeeds, because IPv4 is not internal */
+ {
+ ri = tor_malloc_zero(sizeof(routerinfo_t));
+ tor_addr_parse(&ri->ipv4_addr, "1.0.0.1");
+ tt_int_op(dirserv_router_has_valid_address(ri), OP_EQ, 0);
+ tor_free(ri);
+ }
+
+ done:
+ tor_free(ri);
+ UNMOCK(get_options);
+}
+
#define ADDRESS_TEST(name, flags) \
{ #name, test_address_ ## name, flags, NULL, NULL }
+#define ADDRESS_TEST_STR_ARG(name, flags, str_arg) \
+ { #name "/" str_arg, test_address_ ## name, flags, &passthrough_setup, \
+ (void *)(str_arg) }
struct testcase_t address_tests[] = {
ADDRESS_TEST(udp_socket_trick_whitebox, TT_FORK),
@@ -1202,5 +1361,8 @@ struct testcase_t address_tests[] = {
ADDRESS_TEST(tor_addr_to_mapped_ipv4h, 0),
ADDRESS_TEST(tor_addr_eq_ipv4h, 0),
ADDRESS_TEST(tor_addr_in_same_network_family, 0),
+ ADDRESS_TEST(tor_node_in_same_network_family, 0),
+ ADDRESS_TEST(dirserv_router_addr_private, 0),
+ ADDRESS_TEST_STR_ARG(dirserv_router_addr_private, 0, "allow_private"),
END_OF_TESTCASES
};
diff --git a/src/test/test_address_set.c b/src/test/test_address_set.c
index 4e55d71ff4..37688f4c1d 100644
--- a/src/test/test_address_set.c
+++ b/src/test/test_address_set.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -17,6 +17,7 @@
#include "feature/nodelist/routerstatus_st.h"
#include "test/test.h"
+#include "test/rng_test_helpers.h"
static networkstatus_t *dummy_ns = NULL;
static networkstatus_t *
@@ -62,6 +63,10 @@ test_contains(void *arg)
tor_addr_parse(&addr_v4, "42.42.42.42");
uint32_t ipv4h = tor_addr_to_ipv4h(&addr_v4);
+ /* Use our deterministic RNG since the address set uses a bloom filter
+ * internally. */
+ testing_enable_deterministic_rng();
+
/* Make it very big so the chance of failing the contain test will be
* extremely rare. */
set = address_set_new(1024);
@@ -89,6 +94,8 @@ test_contains(void *arg)
done:
address_set_free(set);
+
+ testing_disable_deterministic_rng();
}
static void
@@ -105,6 +112,12 @@ test_nodelist(void *arg)
mock_networkstatus_get_latest_consensus_by_flavor);
MOCK(get_estimated_address_per_node,
mock_get_estimated_address_per_node);
+ MOCK(dirlist_add_trusted_dir_addresses,
+ mock_dirlist_add_trusted_dir_addresses);
+
+ /* Use our deterministic RNG since the address set, used for
+ * nodelist_probably_contains_address() uses a bloom filter internally. */
+ testing_enable_deterministic_rng();
dummy_ns = tor_malloc_zero(sizeof(*dummy_ns));
dummy_ns->flavor = FLAV_MICRODESC;
@@ -112,7 +125,6 @@ test_nodelist(void *arg)
tor_addr_t addr_v4, addr_v6, dummy_addr;
tor_addr_parse(&addr_v4, "42.42.42.42");
- uint32_t ipv4h = tor_addr_to_ipv4h(&addr_v4);
tor_addr_parse(&addr_v6, "1:2:3:4::");
memset(&dummy_addr, 'A', sizeof(dummy_addr));
@@ -120,7 +132,10 @@ test_nodelist(void *arg)
* (the_nodelist->node_addrs) so we will fail the contain test rarely. */
addr_per_node = 1024;
- /* No node no nothing. The lookups should be empty. */
+ /* No node no nothing. The lookups should be empty. We've mocked the
+ * dirlist_add_trusted_dir_addresses in order for _no_ authorities to be
+ * added to the filter else it makes this test to trigger many false
+ * positive. */
nodelist_set_consensus(dummy_ns);
/* The address set should be empty. */
@@ -143,9 +158,9 @@ test_nodelist(void *arg)
memcpy(rs->descriptor_digest, md->digest, DIGEST256_LEN);
/* Setup the rs, ri and md addresses. */
- rs->addr = ipv4h;
+ tor_addr_copy(&rs->ipv4_addr, &addr_v4);
tor_addr_parse(&rs->ipv6_addr, "1:2:3:4::");
- ri->addr = ipv4h;
+ tor_addr_copy(&ri->ipv4_addr, &addr_v4);
tor_addr_parse(&ri->ipv6_addr, "1:2:3:4::");
tor_addr_parse(&md->ipv6_addr, "1:2:3:4::");
@@ -174,6 +189,9 @@ test_nodelist(void *arg)
UNMOCK(networkstatus_get_latest_consensus);
UNMOCK(networkstatus_get_latest_consensus_by_flavor);
UNMOCK(get_estimated_address_per_node);
+ UNMOCK(dirlist_add_trusted_dir_addresses);
+
+ testing_disable_deterministic_rng();
}
/** Test that the no-reentry exit filter works as intended */
@@ -222,11 +240,11 @@ test_exit_no_reentry(void *arg)
memcpy(rs->descriptor_digest, md->digest, DIGEST256_LEN);
/* Setup the rs, ri and md addresses. */
- rs->addr = tor_addr_to_ipv4h(&addr_v4);
- rs->or_port = 444;
+ tor_addr_copy(&rs->ipv4_addr, &addr_v4);
+ rs->ipv4_orport = 444;
tor_addr_parse(&rs->ipv6_addr, "1:2:3:4::");
rs->ipv6_orport = 666;
- ri->addr = tor_addr_to_ipv4h(&addr_v4);
+ tor_addr_copy(&ri->ipv4_addr, &addr_v4);
tor_addr_parse(&ri->ipv6_addr, "1:2:3:4::");
tor_addr_parse(&md->ipv6_addr, "1:2:3:4::");
diff --git a/src/test/test_bridges.c b/src/test/test_bridges.c
index 879ae6636b..1942a8cb89 100644
--- a/src/test/test_bridges.c
+++ b/src/test/test_bridges.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -550,8 +550,6 @@ test_bridges_get_transport_by_bridge_addrport_no_ptlist(void *arg)
sweep_bridge_list();
}
-#define PT_PRIVATE
-
/**
* Calling get_transport_by_bridge_addrport() with the address and port of a
* configured bridge which uses a pluggable transport should return 0 and set
@@ -594,8 +592,12 @@ test_bridges_get_transport_by_bridge_addrport(void *arg)
static void
test_bridges_node_is_a_configured_bridge(void *arg)
{
- routerinfo_t ri_ipv4 = { .addr = 0x06060606, .or_port = 6666 };
- routerstatus_t rs_ipv4 = { .addr = 0x06060606, .or_port = 6666 };
+
+ routerinfo_t ri_ipv4 = { .ipv4_orport = 6666 };
+ tor_addr_parse(&ri_ipv4.ipv4_addr, "6.6.6.6");
+
+ routerstatus_t rs_ipv4 = { .ipv4_orport = 6666 };
+ tor_addr_parse(&rs_ipv4.ipv4_addr, "6.6.6.6");
routerinfo_t ri_ipv6 = { .ipv6_orport = 6666 };
tor_addr_parse(&(ri_ipv6.ipv6_addr),
@@ -634,8 +636,8 @@ test_bridges_node_is_a_configured_bridge(void *arg)
/* It won't match bridge1, though, since bridge1 has a digest, and this
isn't it! */
- node_ri_ipv4.ri->addr = 0x06060607;
- node_ri_ipv4.ri->or_port = 6667;
+ tor_addr_parse(&node_ri_ipv4.ri->ipv4_addr, "6.6.6.7");
+ node_ri_ipv4.ri->ipv4_orport = 6667;
tt_assert(! node_is_a_configured_bridge(&node_ri_ipv4));
/* If we set the fingerprint right, though, it will match. */
base16_decode(node_ri_ipv4.identity, DIGEST_LEN,
diff --git a/src/test/test_bt.sh b/src/test/test_bt.sh
index df8bcb8eda..312905a4e2 100755
--- a/src/test/test_bt.sh
+++ b/src/test/test_bt.sh
@@ -3,8 +3,6 @@
exitcode=0
-ulimit -c 0
-
export ASAN_OPTIONS="handle_segv=0:allow_user_segv_handler=1"
"${builddir:-.}/src/test/test-bt-cl" backtraces || exit $?
"${builddir:-.}/src/test/test-bt-cl" assert 2>&1 | "${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/bt_test.py" || exitcode="$?"
diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c
index 0c15a02ee4..5f9a88705c 100644
--- a/src/test/test_bt_cl.c
+++ b/src/test/test_bt_cl.c
@@ -1,9 +1,12 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include <stdio.h>
#include <stdlib.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
/* To prevent 'assert' from going away. */
#undef TOR_COVERAGE
@@ -30,7 +33,7 @@ int a_tangled_web(int x) NOINLINE;
int we_weave(int x) NOINLINE;
#ifdef HAVE_CFLAG_WNULL_DEREFERENCE
-DISABLE_GCC_WARNING(null-dereference)
+DISABLE_GCC_WARNING("-Wnull-dereference")
#endif
int
crash(int x)
@@ -43,7 +46,7 @@ crash(int x)
*(volatile int *)0 = 0;
#endif /* defined(__clang_analyzer__) || defined(__COVERITY__) */
} else if (crashtype == 1) {
- tor_assert(1 == 0);
+ tor_assertf(1 == 0, "%d != %d", 1, 0);
} else if (crashtype == -1) {
;
}
@@ -52,7 +55,7 @@ crash(int x)
return crashtype;
}
#ifdef HAVE_CFLAG_WNULL_DEREFERENCE
-ENABLE_GCC_WARNING(null-dereference)
+ENABLE_GCC_WARNING("-Wnull-dereference")
#endif
int
@@ -88,6 +91,11 @@ main(int argc, char **argv)
return 1;
}
+#ifdef HAVE_SYS_RESOURCE_H
+ struct rlimit rlim = { .rlim_cur = 0, .rlim_max = 0 };
+ setrlimit(RLIMIT_CORE, &rlim);
+#endif
+
#if !(defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION))
puts("Backtrace reporting is not supported on this platform");
diff --git a/src/test/test_btrack.c b/src/test/test_btrack.c
new file mode 100644
index 0000000000..2b2f34fc23
--- /dev/null
+++ b/src/test/test_btrack.c
@@ -0,0 +1,129 @@
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "core/or/or.h"
+
+#include "test/test.h"
+#include "test/test_helpers.h"
+#include "test/log_test_helpers.h"
+
+#define OCIRC_EVENT_PRIVATE
+#define ORCONN_EVENT_PRIVATE
+#include "core/or/ocirc_event.h"
+#include "core/or/orconn_event.h"
+
+static void
+send_state(const orconn_state_msg_t *msg_in)
+{
+ orconn_state_msg_t *msg = tor_malloc(sizeof(*msg));
+
+ *msg = *msg_in;
+ orconn_state_publish(msg);
+}
+
+static void
+send_status(const orconn_status_msg_t *msg_in)
+{
+ orconn_status_msg_t *msg = tor_malloc(sizeof(*msg));
+
+ *msg = *msg_in;
+ orconn_status_publish(msg);
+}
+
+static void
+send_chan(const ocirc_chan_msg_t *msg_in)
+{
+ ocirc_chan_msg_t *msg = tor_malloc(sizeof(*msg));
+
+ *msg = *msg_in;
+ ocirc_chan_publish(msg);
+}
+
+static void
+test_btrack_launch(void *arg)
+{
+ orconn_state_msg_t conn;
+ ocirc_chan_msg_t circ;
+ memset(&conn, 0, sizeof(conn));
+ memset(&circ, 0, sizeof(circ));
+
+ (void)arg;
+ conn.gid = 1;
+ conn.chan = 1;
+ conn.proxy_type = PROXY_NONE;
+ conn.state = OR_CONN_STATE_CONNECTING;
+
+ setup_full_capture_of_logs(LOG_DEBUG);
+ send_state(&conn);
+ expect_log_msg_containing("ORCONN gid=1 chan=1 proxy_type=0 state=1");
+ expect_no_log_msg_containing("ORCONN BEST_");
+ teardown_capture_of_logs();
+
+ circ.chan = 1;
+ circ.onehop = true;
+
+ setup_full_capture_of_logs(LOG_DEBUG);
+ send_chan(&circ);
+ expect_log_msg_containing("ORCONN LAUNCH chan=1 onehop=1");
+ expect_log_msg_containing("ORCONN BEST_ANY state -1->1 gid=1");
+ teardown_capture_of_logs();
+
+ conn.gid = 2;
+ conn.chan = 2;
+
+ setup_full_capture_of_logs(LOG_DEBUG);
+ send_state(&conn);
+ expect_log_msg_containing("ORCONN gid=2 chan=2 proxy_type=0 state=1");
+ expect_no_log_msg_containing("ORCONN BEST_");
+ teardown_capture_of_logs();
+
+ circ.chan = 2;
+ circ.onehop = false;
+
+ setup_full_capture_of_logs(LOG_DEBUG);
+ send_chan(&circ);
+ expect_log_msg_containing("ORCONN LAUNCH chan=2 onehop=0");
+ expect_log_msg_containing("ORCONN BEST_AP state -1->1 gid=2");
+ teardown_capture_of_logs();
+
+ done:
+ ;
+}
+
+static void
+test_btrack_delete(void *arg)
+{
+ orconn_state_msg_t state;
+ orconn_status_msg_t status;
+ memset(&state, 0, sizeof(state));
+ memset(&status, 0, sizeof(status));
+
+ (void)arg;
+ state.gid = 1;
+ state.chan = 1;
+ state.proxy_type = PROXY_NONE;
+ state.state = OR_CONN_STATE_CONNECTING;
+
+ setup_full_capture_of_logs(LOG_DEBUG);
+ send_state(&state);
+ expect_log_msg_containing("ORCONN gid=1 chan=1 proxy_type=0");
+ teardown_capture_of_logs();
+
+ status.gid = 1;
+ status.status = OR_CONN_EVENT_CLOSED;
+ status.reason = 0;
+
+ setup_full_capture_of_logs(LOG_DEBUG);
+ send_status(&status);
+ expect_log_msg_containing("ORCONN DELETE gid=1 status=3 reason=0");
+ teardown_capture_of_logs();
+
+ done:
+ ;
+}
+
+struct testcase_t btrack_tests[] = {
+ { "launch", test_btrack_launch, TT_FORK, &helper_pubsub_setup, NULL },
+ { "delete", test_btrack_delete, TT_FORK, &helper_pubsub_setup, NULL },
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c
index 3e7364a5c8..fbaa628fd7 100644
--- a/src/test/test_buffers.c
+++ b/src/test/test_buffers.c
@@ -1,12 +1,12 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define BUFFERS_PRIVATE
#define PROTO_HTTP_PRIVATE
#include "core/or/or.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "lib/tls/buffers_tls.h"
#include "lib/tls/tortls.h"
#include "lib/compress/compress.h"
diff --git a/src/test/test_bwmgt.c b/src/test/test_bwmgt.c
index 5a013aa268..4cf83e45d0 100644
--- a/src/test/test_bwmgt.c
+++ b/src/test/test_bwmgt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,18 +6,70 @@
* \brief tests for bandwidth management / token bucket functions
*/
+#define CONFIG_PRIVATE
+#define CONNECTION_PRIVATE
+#define DIRAUTH_SYS_PRIVATE
#define TOKEN_BUCKET_PRIVATE
#include "core/or/or.h"
-#include "test/test.h"
+#include "app/config/config.h"
+#include "core/mainloop/connection.h"
+#include "feature/dirauth/dirauth_sys.h"
+#include "feature/dircommon/directory.h"
+#include "feature/nodelist/microdesc.h"
+#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/nodelist.h"
+#include "feature/nodelist/routerlist.h"
+#include "lib/crypt_ops/crypto_rand.h"
#include "lib/evloop/token_bucket.h"
+#include "test/test.h"
+#include "test/test_helpers.h"
+
+#include "app/config/or_options_st.h"
+#include "core/or/connection_st.h"
+#include "feature/dirauth/dirauth_options_st.h"
+#include "feature/nodelist/microdesc_st.h"
+#include "feature/nodelist/networkstatus_st.h"
+#include "feature/nodelist/routerinfo_st.h"
+#include "feature/nodelist/routerstatus_st.h"
// an imaginary time, in timestamp units. Chosen so it will roll over.
static const uint32_t START_TS = UINT32_MAX-10;
static const int32_t KB = 1024;
static const uint32_t GB = (UINT64_C(1) << 30);
+static or_options_t mock_options;
+
+static const or_options_t *
+mock_get_options(void)
+{
+ return &mock_options;
+}
+
+static networkstatus_t *dummy_ns = NULL;
+static networkstatus_t *
+mock_networkstatus_get_latest_consensus(void)
+{
+ return dummy_ns;
+}
+
+static networkstatus_t *
+mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
+{
+ tor_assert(f == FLAV_MICRODESC);
+ return dummy_ns;
+}
+
+/* Number of address a single node_t can have. Default to the production
+ * value. This is to control the size of the bloom filter. */
+static int addr_per_node = 2;
+static int
+mock_get_estimated_address_per_node(void)
+{
+ return addr_per_node;
+}
+
static void
test_bwmgt_token_buf_init(void *arg)
{
@@ -220,8 +272,167 @@ test_bwmgt_token_buf_helpers(void *arg)
;
}
+static void
+test_bwmgt_dir_conn_global_write_low(void *arg)
+{
+ bool ret;
+ int addr_family;
+ connection_t *conn = NULL;
+ routerstatus_t *rs = NULL; microdesc_t *md = NULL; routerinfo_t *ri = NULL;
+ tor_addr_t relay_addr;
+ dirauth_options_t *dirauth_opts = NULL;
+
+ (void) arg;
+
+ memset(&mock_options, 0, sizeof(or_options_t));
+ MOCK(networkstatus_get_latest_consensus,
+ mock_networkstatus_get_latest_consensus);
+ MOCK(networkstatus_get_latest_consensus_by_flavor,
+ mock_networkstatus_get_latest_consensus_by_flavor);
+ MOCK(get_estimated_address_per_node,
+ mock_get_estimated_address_per_node);
+
+ /*
+ * The following is rather complex but that is what it takes to add a dummy
+ * consensus with a valid routerlist which will populate our node address
+ * set that we need to lookup to test the known relay code path.
+ *
+ * We MUST do that before we MOCK(get_options) else it is another world of
+ * complexity.
+ */
+
+ /* This will be the address of our relay. */
+ tor_addr_parse(&relay_addr, "1.2.3.4");
+
+ /* We'll now add a relay into our routerlist and see if we let it. */
+ dummy_ns = tor_malloc_zero(sizeof(*dummy_ns));
+ dummy_ns->flavor = FLAV_MICRODESC;
+ dummy_ns->routerstatus_list = smartlist_new();
+
+ md = tor_malloc_zero(sizeof(*md));
+ ri = tor_malloc_zero(sizeof(*ri));
+ rs = tor_malloc_zero(sizeof(*rs));
+ crypto_rand(rs->identity_digest, sizeof(rs->identity_digest));
+ crypto_rand(md->digest, sizeof(md->digest));
+ memcpy(rs->descriptor_digest, md->digest, DIGEST256_LEN);
+
+ /* Set IP address. */
+ tor_addr_copy(&rs->ipv4_addr, &relay_addr);
+ tor_addr_copy(&ri->ipv4_addr, &rs->ipv4_addr);
+ /* Add the rs to the consensus becoming a node_t. */
+ smartlist_add(dummy_ns->routerstatus_list, rs);
+
+ /* Add all configured authorities (hardcoded) before we set the consensus so
+ * the address set exists. */
+ ret = consider_adding_dir_servers(&mock_options, &mock_options);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* This will make the nodelist bloom filter very large
+ * (the_nodelist->node_addrs) so we will fail the contain test rarely. */
+ addr_per_node = 1024;
+
+ nodelist_set_consensus(dummy_ns);
+
+ dirauth_opts = tor_malloc_zero(sizeof(dirauth_options_t));
+ dirauth_opts->AuthDirRejectRequestsUnderLoad = 0;
+ dirauth_set_options(dirauth_opts);
+
+ /* Ok, now time to control which options we use. */
+ MOCK(get_options, mock_get_options);
+
+ /* Set ourselves as an authoritative dir. */
+ mock_options.AuthoritativeDir = 1;
+ mock_options.V3AuthoritativeDir = 1;
+ mock_options.UseDefaultFallbackDirs = 0;
+
+ /* This will set our global bucket to 1 byte and thus we will hit the
+ * banwdith limit in our test. */
+ mock_options.BandwidthRate = 1;
+ mock_options.BandwidthBurst = 1;
+
+ /* Else an IPv4 address screams. */
+ mock_options.ClientUseIPv4 = 1;
+ mock_options.ClientUseIPv6 = 1;
+
+ /* Initialize the global buckets. */
+ connection_bucket_init();
+
+ /* The address "127.0.0.1" is set with this helper. */
+ conn = test_conn_get_connection(DIR_CONN_STATE_MIN_, CONN_TYPE_DIR,
+ DIR_PURPOSE_MIN_);
+ tt_assert(conn);
+
+ /* First try a non authority non relay IP thus a client but we are not
+ * configured to reject requests under load so we should get a false value
+ * that our limit is _not_ low. */
+ addr_family = tor_addr_parse(&conn->addr, "1.1.1.1");
+ tt_int_op(addr_family, OP_EQ, AF_INET);
+ ret = connection_dir_is_global_write_low(conn, INT_MAX);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Now, we will reject requests under load so try again a non authority non
+ * relay IP thus a client. We should get a warning that our limit is too
+ * low. */
+ dirauth_opts->AuthDirRejectRequestsUnderLoad = 1;
+
+ addr_family = tor_addr_parse(&conn->addr, "1.1.1.1");
+ tt_int_op(addr_family, OP_EQ, AF_INET);
+ ret = connection_dir_is_global_write_low(conn, INT_MAX);
+ tt_int_op(ret, OP_EQ, 1);
+
+ /* Now, lets try with a connection address from moria1. It should always
+ * pass even though our limit is too low. */
+ addr_family = tor_addr_parse(&conn->addr, "128.31.0.39");
+ tt_int_op(addr_family, OP_EQ, AF_INET);
+ ret = connection_dir_is_global_write_low(conn, INT_MAX);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* IPv6 testing of gabelmoo. */
+ addr_family = tor_addr_parse(&conn->addr, "[2001:638:a000:4140::ffff:189]");
+ tt_int_op(addr_family, OP_EQ, AF_INET6);
+ ret = connection_dir_is_global_write_low(conn, INT_MAX);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Lets retry with a known relay address. It should pass. Possible due to
+ * our consensus setting above. */
+ memcpy(&conn->addr, &relay_addr, sizeof(tor_addr_t));
+ ret = connection_dir_is_global_write_low(conn, INT_MAX);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Lets retry with a random IP that is not an authority nor a relay. */
+ addr_family = tor_addr_parse(&conn->addr, "1.2.3.4");
+ tt_int_op(addr_family, OP_EQ, AF_INET);
+ ret = connection_dir_is_global_write_low(conn, INT_MAX);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Finally, just make sure it still denies an IP if we are _not_ a v3
+ * directory authority. */
+ mock_options.V3AuthoritativeDir = 0;
+ addr_family = tor_addr_parse(&conn->addr, "1.2.3.4");
+ tt_int_op(addr_family, OP_EQ, AF_INET);
+ ret = connection_dir_is_global_write_low(conn, INT_MAX);
+ tt_int_op(ret, OP_EQ, 1);
+
+ /* Random IPv6 should not be allowed. */
+ addr_family = tor_addr_parse(&conn->addr, "[CAFE::ACAB]");
+ tt_int_op(addr_family, OP_EQ, AF_INET6);
+ ret = connection_dir_is_global_write_low(conn, INT_MAX);
+ tt_int_op(ret, OP_EQ, 1);
+
+ done:
+ connection_free_minimal(conn);
+ routerstatus_free(rs); routerinfo_free(ri); microdesc_free(md);
+ smartlist_clear(dummy_ns->routerstatus_list);
+ networkstatus_vote_free(dummy_ns);
+
+ UNMOCK(get_estimated_address_per_node);
+ UNMOCK(networkstatus_get_latest_consensus);
+ UNMOCK(networkstatus_get_latest_consensus_by_flavor);
+ UNMOCK(get_options);
+}
+
#define BWMGT(name) \
- { #name, test_bwmgt_ ## name , 0, NULL, NULL }
+ { #name, test_bwmgt_ ## name , TT_FORK, NULL, NULL }
struct testcase_t bwmgt_tests[] = {
BWMGT(token_buf_init),
@@ -229,5 +440,7 @@ struct testcase_t bwmgt_tests[] = {
BWMGT(token_buf_dec),
BWMGT(token_buf_refill),
BWMGT(token_buf_helpers),
+
+ BWMGT(dir_conn_global_write_low),
END_OF_TESTCASES
};
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index fc5367557d..f9ff101c98 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -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_cell_queue.c b/src/test/test_cell_queue.c
index 8fc1da031e..b778c07802 100644
--- a/src/test/test_cell_queue.c
+++ b/src/test/test_cell_queue.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITLIST_PRIVATE
diff --git a/src/test/test_channel.c b/src/test/test_channel.c
index afb7db813c..d43f6e010a 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -1,8 +1,8 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define TOR_CHANNEL_INTERNAL_
-#define CHANNEL_PRIVATE_
+#define CHANNEL_OBJECT_PRIVATE
+#define CHANNEL_FILE_PRIVATE
#include "core/or/or.h"
#include "core/or/channel.h"
/* For channel_note_destroy_not_pending */
@@ -16,6 +16,10 @@
/* For packed_cell stuff */
#define RELAY_PRIVATE
#include "core/or/relay.h"
+/* For channel_tls_t object and private functions. */
+#define CHANNEL_OBJECT_PRIVATE
+#define CHANNELTLS_PRIVATE
+#include "core/or/channeltls.h"
/* For init/free stuff */
#include "core/or/scheduler.h"
#include "feature/nodelist/networkstatus.h"
@@ -25,6 +29,8 @@
#include "core/or/origin_circuit_st.h"
#include "feature/nodelist/routerstatus_st.h"
#include "core/or/var_cell_st.h"
+#include "core/or/or_connection_st.h"
+#include "lib/net/inaddr.h"
/* Test suite stuff */
#include "test/log_test_helpers.h"
@@ -34,8 +40,6 @@
static int test_chan_accept_cells = 0;
static int test_chan_fixed_cells_recved = 0;
static cell_t * test_chan_last_seen_fixed_cell_ptr = NULL;
-static int test_chan_var_cells_recved = 0;
-static var_cell_t * test_chan_last_seen_var_cell_ptr = NULL;
static int test_cells_written = 0;
static int test_doesnt_want_writes_count = 0;
static int test_dumpstats_calls = 0;
@@ -112,24 +116,6 @@ chan_test_dumpstats(channel_t *ch, int severity)
return;
}
-/*
- * Handle an incoming variable-size cell for unit tests
- */
-
-static void
-chan_test_var_cell_handler(channel_t *ch,
- var_cell_t *var_cell)
-{
- tt_assert(ch);
- tt_assert(var_cell);
-
- test_chan_last_seen_var_cell_ptr = var_cell;
- ++test_chan_var_cells_recved;
-
- done:
- return;
-}
-
static void
chan_test_close(channel_t *ch)
{
@@ -176,16 +162,23 @@ chan_test_finish_close(channel_t *ch)
}
static const char *
-chan_test_get_remote_descr(channel_t *ch, int flags)
+chan_test_describe_peer(const channel_t *ch)
{
tt_assert(ch);
- tt_int_op(flags & ~(GRD_FLAG_ORIGINAL | GRD_FLAG_ADDR_ONLY), OP_EQ, 0);
done:
return "Fake channel for unit tests; no real endpoint";
}
static int
+chan_test_get_remote_addr(const channel_t *ch, tor_addr_t *out)
+{
+ (void)ch;
+ tor_addr_from_ipv4h(out, 0x7f000001);
+ return 1;
+}
+
+static int
chan_test_num_cells_writeable(channel_t *ch)
{
tt_assert(ch);
@@ -281,7 +274,8 @@ new_fake_channel(void)
chan->close = chan_test_close;
chan->num_cells_writeable = chan_test_num_cells_writeable;
- chan->get_remote_descr = chan_test_get_remote_descr;
+ chan->describe_peer = chan_test_describe_peer;
+ chan->get_remote_addr = chan_test_get_remote_addr;
chan->write_packed_cell = chan_test_write_packed_cell;
chan->write_var_cell = chan_test_write_var_cell;
chan->state = CHANNEL_STATE_OPEN;
@@ -487,11 +481,8 @@ test_channel_dumpstats(void *arg)
/* Receive path */
channel_set_cell_handlers(ch,
- chan_test_cell_handler,
- chan_test_var_cell_handler);
+ chan_test_cell_handler);
tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, chan_test_cell_handler);
- tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ,
- chan_test_var_cell_handler);
cell = tor_malloc_zero(sizeof(*cell));
old_count = test_chan_fixed_cells_recved;
channel_process_cell(ch, cell);
@@ -593,7 +584,6 @@ test_channel_outbound_cell(void *arg)
circuit_set_n_circid_chan(TO_CIRCUIT(circ), 42, chan);
tt_int_op(channel_num_circuits(chan), OP_EQ, 1);
/* Test the cmux state. */
- tt_ptr_op(TO_CIRCUIT(circ)->n_mux, OP_EQ, chan->cmux);
tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)),
OP_EQ, 1);
@@ -718,7 +708,7 @@ test_channel_inbound_cell(void *arg)
/* Setup incoming cell handlers. We don't care about var cell, the channel
* layers is not handling those. */
- channel_set_cell_handlers(chan, chan_test_cell_handler, NULL);
+ channel_set_cell_handlers(chan, chan_test_cell_handler);
tt_ptr_op(chan->cell_handler, OP_EQ, chan_test_cell_handler);
/* Now process the cell, we should see it. */
old_count = test_chan_fixed_cells_recved;
@@ -739,7 +729,7 @@ test_channel_inbound_cell(void *arg)
tt_int_op(chan->reason_for_closing, OP_EQ, CHANNEL_CLOSE_REQUESTED);
tt_int_op(test_close_called, OP_EQ, old_count + 1);
- /* This closes the channe so it calls in the scheduler, make sure of it. */
+ /* This closes the channel so it calls in the scheduler, make sure of it. */
old_count = test_releases_count;
chan_test_finish_close(chan);
tt_int_op(test_releases_count, OP_EQ, old_count + 1);
@@ -1345,7 +1335,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);
@@ -1355,6 +1345,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. */
@@ -1388,7 +1381,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,
+ false, &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1396,16 +1390,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,
+ false, &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,
+ false, &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan1);
tt_int_op(launch, OP_EQ, 0);
@@ -1416,7 +1412,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,
+ false, &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1425,7 +1422,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,
+ false, &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1435,8 +1433,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,
+ false, &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Not connected. Connecting.");
tt_int_op(launch, OP_EQ, 1);
@@ -1445,7 +1444,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,
+ false, &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connection in progress; waiting.");
tt_int_op(launch, OP_EQ, 0);
@@ -1454,7 +1454,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,
+ false, &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1464,7 +1465,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,
+ false, &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
" Launching a new one.");
@@ -1475,7 +1477,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,
+ false, &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
" Launching a new one.");
@@ -1539,9 +1542,61 @@ test_channel_listener(void *arg)
channel_listener_dump_statistics(chan, LOG_INFO);
done:
+ if (chan) {
+ channel_listener_unregister(chan);
+ tor_free(chan);
+ }
channel_free_all();
}
+#define TEST_SETUP_MATCHES_ADDR(orcon, addr, src, rv) STMT_BEGIN \
+ rv = tor_inet_pton(addr.family, src, &addr.addr); \
+ tt_int_op(rv, OP_EQ, 1); \
+ orcon->base_.addr = addr; \
+ STMT_END;
+
+#define TEST_MATCHES_ADDR(chan, addr4, addr6, rv, exp) STMT_BEGIN \
+ rv = channel_matches_target_addr_for_extend(chan, addr4, addr6); \
+ tt_int_op(rv, OP_EQ, exp); \
+ STMT_END;
+
+static void
+test_channel_matches_target_addr_for_extend(void *arg)
+{
+ (void) arg;
+
+ channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan));
+ or_connection_t *orcon = tor_malloc_zero(sizeof(*orcon));
+ channel_t *chan = &(tlschan->base_);
+ tor_addr_t addr;
+ int rv;
+
+ tlschan->conn = orcon;
+ channel_tls_common_init(tlschan);
+
+ /* Test for IPv4 addresses. */
+ addr.family = AF_INET;
+ TEST_SETUP_MATCHES_ADDR(orcon, addr, "1.2.3.4", rv);
+ TEST_MATCHES_ADDR(chan, &addr, NULL, rv, 1);
+
+ tor_inet_pton(addr.family, "2.5.3.4", &addr.addr);
+ TEST_MATCHES_ADDR(chan, &addr, NULL, rv, 0);
+
+ /* Test for IPv6 addresses. */
+ addr.family = AF_INET6;
+ TEST_SETUP_MATCHES_ADDR(orcon, addr, "3:4:7:1:9:8:09:10", rv);
+ TEST_MATCHES_ADDR(chan, NULL, &addr, rv, 1);
+
+ tor_inet_pton(addr.family, "::", &addr.addr);
+ TEST_MATCHES_ADDR(chan, NULL, &addr, rv, 0);
+
+ done:
+ circuitmux_clear_policy(chan->cmux);
+ circuitmux_free(chan->cmux);
+ tor_free(orcon);
+ tor_free(tlschan);
+}
+
struct testcase_t channel_tests[] = {
{ "inbound_cell", test_channel_inbound_cell, TT_FORK,
NULL, NULL },
@@ -1563,5 +1618,7 @@ struct testcase_t channel_tests[] = {
NULL, NULL },
{ "listener", test_channel_listener, TT_FORK,
NULL, NULL },
+ { "matches_target", test_channel_matches_target_addr_for_extend, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c
index 5da2d81377..63a591583d 100644
--- a/src/test/test_channelpadding.c
+++ b/src/test/test_channelpadding.c
@@ -1,7 +1,7 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define MAINLOOP_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define TOR_TIMERS_PRIVATE
@@ -21,7 +21,7 @@
#include "test/log_test_helpers.h"
#include "lib/tls/tortls.h"
#include "lib/evloop/timers.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "core/or/cell_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -289,8 +289,6 @@ test_channelpadding_timers(void *arg)
channel_t *chans[CHANNELS_TO_TEST];
(void)arg;
- tor_libevent_postfork();
-
if (!connection_array)
connection_array = smartlist_new();
@@ -393,7 +391,6 @@ test_channelpadding_killonehop(void *arg)
channelpadding_decision_t decision;
int64_t new_time;
(void)arg;
- tor_libevent_postfork();
routerstatus_t *relay = tor_malloc_zero(sizeof(routerstatus_t));
monotime_init();
@@ -502,8 +499,6 @@ test_channelpadding_consensus(void *arg)
int64_t new_time;
(void)arg;
- tor_libevent_postfork();
-
/*
* Params tested:
* nf_pad_before_usage
@@ -898,8 +893,6 @@ test_channelpadding_decide_to_pad_channel(void *arg)
connection_array = smartlist_new();
(void)arg;
- tor_libevent_postfork();
-
monotime_init();
monotime_enable_test_mocking();
monotime_set_mock_time_nsec(1);
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
index 10513e451d..0227779e8b 100644
--- a/src/test/test_channeltls.c
+++ b/src/test/test_channeltls.c
@@ -1,19 +1,20 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include <math.h>
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#include "core/or/or.h"
#include "lib/net/address.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "core/or/channel.h"
#include "core/or/channeltls.h"
#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"
@@ -37,13 +38,13 @@ static or_connection_t * tlschan_connection_or_connect_mock(
const char *digest,
const ed25519_public_key_t *ed_id,
channel_tls_t *tlschan);
-static int tlschan_is_local_addr_mock(const tor_addr_t *addr);
+static bool tlschan_resolved_addr_is_local_mock(const tor_addr_t *addr);
/* Fake close method */
static void tlschan_fake_close_method(channel_t *chan);
/* Flags controlling behavior of channeltls unit test mocks */
-static int tlschan_local = 0;
+static bool tlschan_local = false;
static const buf_t * tlschan_buf_datalen_mock_target = NULL;
static size_t tlschan_buf_datalen_mock_size = 0;
@@ -66,9 +67,9 @@ test_channeltls_create(void *arg)
test_addr.addr.in_addr.s_addr = htonl(0x01020304);
/* For this test we always want the address to be treated as non-local */
- tlschan_local = 0;
- /* Install is_local_addr() mock */
- MOCK(is_local_addr, tlschan_is_local_addr_mock);
+ tlschan_local = false;
+ /* Install is_local_to_resolve_addr() mock */
+ MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
/* Install mock for connection_or_connect() */
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
@@ -91,7 +92,7 @@ test_channeltls_create(void *arg)
}
UNMOCK(connection_or_connect);
- UNMOCK(is_local_addr);
+ UNMOCK(is_local_to_resolve_addr);
return;
}
@@ -115,9 +116,9 @@ test_channeltls_num_bytes_queued(void *arg)
test_addr.addr.in_addr.s_addr = htonl(0x01020304);
/* For this test we always want the address to be treated as non-local */
- tlschan_local = 0;
- /* Install is_local_addr() mock */
- MOCK(is_local_addr, tlschan_is_local_addr_mock);
+ tlschan_local = false;
+ /* Install is_local_to_resolve_addr() mock */
+ MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
/* Install mock for connection_or_connect() */
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
@@ -177,7 +178,7 @@ test_channeltls_num_bytes_queued(void *arg)
}
UNMOCK(connection_or_connect);
- UNMOCK(is_local_addr);
+ UNMOCK(is_local_to_resolve_addr);
return;
}
@@ -200,9 +201,9 @@ test_channeltls_overhead_estimate(void *arg)
test_addr.addr.in_addr.s_addr = htonl(0x01020304);
/* For this test we always want the address to be treated as non-local */
- tlschan_local = 0;
- /* Install is_local_addr() mock */
- MOCK(is_local_addr, tlschan_is_local_addr_mock);
+ tlschan_local = false;
+ /* Install is_local_to_resolve_addr() mock */
+ MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
/* Install mock for connection_or_connect() */
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
@@ -251,7 +252,7 @@ test_channeltls_overhead_estimate(void *arg)
}
UNMOCK(connection_or_connect);
- UNMOCK(is_local_addr);
+ UNMOCK(is_local_to_resolve_addr);
return;
}
@@ -292,7 +293,7 @@ tlschan_connection_or_connect_mock(const tor_addr_t *addr,
result->base_.port = port;
memcpy(result->identity_digest, digest, DIGEST_LEN);
result->chan = tlschan;
- memcpy(&(result->real_addr), addr, sizeof(tor_addr_t));
+ memcpy(&result->base_.addr, addr, sizeof(tor_addr_t));
result->tls = (tor_tls_t *)((void *)(&fake_tortls));
done:
@@ -320,8 +321,8 @@ tlschan_fake_close_method(channel_t *chan)
return;
}
-static int
-tlschan_is_local_addr_mock(const tor_addr_t *addr)
+static bool
+tlschan_resolved_addr_is_local_mock(const tor_addr_t *addr)
{
tt_ptr_op(addr, OP_NE, NULL);
diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c
index 1df74c390a..186a55cc8c 100644
--- a/src/test/test_checkdir.c
+++ b/src/test/test_checkdir.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c
index 538f20781f..299908ce82 100644
--- a/src/test/test_circuitbuild.c
+++ b/src/test/test_circuitbuild.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITBUILD_PRIVATE
@@ -8,18 +8,35 @@
#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/circuituse.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/nodelist/node_select.h"
+#include "feature/relay/circuitbuild_relay.h"
+#include "feature/relay/router.h"
+#include "feature/relay/routermode.h"
+
+#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/routerinfo_st.h"
/* Dummy nodes smartlist for testing */
static smartlist_t dummy_nodes;
@@ -27,11 +44,11 @@ static smartlist_t dummy_nodes;
static extend_info_t dummy_ei;
static int
-mock_count_acceptable_nodes(smartlist_t *nodes)
+mock_count_acceptable_nodes(const smartlist_t *nodes, int direct)
{
(void)nodes;
- return DEFAULT_ROUTE_LEN + 1;
+ return direct ? 1 : DEFAULT_ROUTE_LEN + 1;
}
/* Test route lengths when the caller of new_route_len() doesn't
@@ -114,6 +131,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 +150,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);
}
@@ -167,16 +192,1797 @@ test_upgrade_from_guard_wait(void *arg)
tt_assert(!list);
done:
+ smartlist_free(list);
circuit_free(circ);
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 bool mocked_supports_ed25519_link_authentication = 0;
+static bool
+mock_node_supports_ed25519_link_authentication(const node_t *node,
+ bool 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);
+}
+
+#define NODE_SET_IPV4(node, ipv4_addr_str, ipv4_port) { \
+ tor_addr_parse(&node->ri->ipv4_addr, ipv4_addr_str); \
+ node->ri->ipv4_orport = ipv4_port; \
+ }
+
+#define NODE_CLEAR_IPV4(node) { \
+ tor_addr_make_unspec(&node->ri->ipv4_addr); \
+ node->ri->ipv4_orport = 0; \
+ }
+
+#define NODE_SET_IPV6(node, ipv6_addr_str, ipv6_port) { \
+ tor_addr_parse(&node->ri->ipv6_addr, ipv6_addr_str); \
+ node->ri->ipv6_orport = ipv6_port; \
+ }
+
+/* Test the different cases in circuit_extend_add_ed25519_helper(). */
+static void
+test_circuit_extend_add_ip(void *arg)
+{
+ (void) arg;
+ tor_addr_t ipv4_tmp;
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ extend_cell_t *old_ec = tor_malloc_zero(sizeof(extend_cell_t));
+
+ node_t *fake_node = tor_malloc_zero(sizeof(node_t));
+ routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t));
+
+ MOCK(node_get_by_id, mock_node_get_by_id);
+
+ /* Set up the fake variables for the IPv4 test */
+ fake_node->ri = ri;
+ mocked_node = fake_node;
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ NODE_SET_IPV4(fake_node, PUBLIC_IPV4, VALID_PORT);
+
+ /* Do the IPv4 test */
+ tt_int_op(circuit_extend_add_ipv4_helper(ec), OP_EQ, 0);
+ tor_addr_copy(&ipv4_tmp, &fake_node->ri->ipv4_addr);
+ /* The IPv4 should match */
+ tt_int_op(tor_addr_compare(&ec->orport_ipv4.addr, &ipv4_tmp, CMP_SEMANTIC),
+ OP_EQ, 0);
+ tt_int_op(ec->orport_ipv4.port, OP_EQ, VALID_PORT);
+
+ /* Set up the fake variables for the IPv6 test */
+ memcpy(ec, old_ec, sizeof(extend_cell_t));
+ NODE_CLEAR_IPV4(fake_node);
+ NODE_SET_IPV6(fake_node, PUBLIC_IPV6, VALID_PORT);
+
+ /* Do the IPv6 test */
+ tt_int_op(circuit_extend_add_ipv6_helper(ec), OP_EQ, 0);
+ /* The IPv6 should match */
+ tt_int_op(tor_addr_compare(&ec->orport_ipv6.addr, &fake_node->ri->ipv6_addr,
+ CMP_SEMANTIC), OP_EQ, 0);
+ tt_int_op(ec->orport_ipv6.port, OP_EQ, VALID_PORT);
+
+ /* Cleanup */
+ mocked_node = NULL;
+
+ done:
+ UNMOCK(node_get_by_id);
+
+ tor_free(ec);
+ tor_free(old_ec);
+
+ tor_free(ri);
+ tor_free(fake_node);
+}
+
+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 extend_info_t *ei)
+{
+ (void)ei;
+ 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,
+ bool for_origin_circ,
+ const char **msg_out,
+ int *launch_out)
+{
+ (void)rsa_id_digest;
+ (void)ed_id;
+ (void)target_ipv4_addr;
+ (void)target_ipv6_addr;
+ (void)for_origin_circ;
+
+ /* 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()";
+}
+
+/* Should mock_circuit_deliver_create_cell() expect a direct connection? */
+static bool mock_circuit_deliver_create_cell_expect_direct = false;
+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);
+ /* We expect n_chan for relayed cells. But should we also expect it for
+ * direct connections? */
+ if (!mock_circuit_deliver_create_cell_expect_direct)
+ tt_ptr_op(circ->n_chan, OP_NE, NULL);
+
+ /* We should only ever get relayed cells from extends */
+ tt_int_op(relayed, OP_EQ, !mock_circuit_deliver_create_cell_expect_direct);
+
+ 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_describe_peer,
+ 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_expect_direct = false;
+ 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_describe_peer);
+
+ 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);
+}
+
+/* Test the different cases in origin_circuit_init(). */
+static void
+test_origin_circuit_init(void *arg)
+{
+ (void)arg;
+ origin_circuit_t *origin_circ = NULL;
+
+ /* Init with 0 purpose and 0 flags */
+ origin_circ = origin_circuit_init(0, 0);
+ tt_int_op(origin_circ->base_.purpose, OP_EQ, 0);
+ tt_int_op(origin_circ->base_.state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+ /* The circuits are automatically freed by the circuitlist. */
+
+ /* Init with a purpose */
+ origin_circ = origin_circuit_init(CIRCUIT_PURPOSE_C_GENERAL, 0);
+ tt_int_op(origin_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
+
+ /* Init with each flag */
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_IS_INTERNAL);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_IS_IPV6_SELFTEST);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_NEED_CAPACITY);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_NEED_UPTIME);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_ONEHOP_TUNNEL);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 1);
+
+ done:
+ /* The circuits are automatically freed by the circuitlist. */
+ ;
+}
+
+/* Test the different cases in circuit_send_next_onion_skin(). */
+static void
+test_circuit_send_next_onion_skin(void *arg)
+{
+ (void)arg;
+ origin_circuit_t *origin_circ = NULL;
+ struct timeval circ_start_time;
+ memset(&circ_start_time, 0, sizeof(circ_start_time));
+
+ extend_info_t fakehop;
+ memset(&fakehop, 0, sizeof(fakehop));
+ extend_info_t *single_fakehop = &fakehop;
+ extend_info_t *multi_fakehop[DEFAULT_ROUTE_LEN] = {&fakehop,
+ &fakehop,
+ &fakehop};
+
+ extend_info_t ipv6_hop;
+ memset(&ipv6_hop, 0, sizeof(ipv6_hop));
+ tor_addr_parse(&ipv6_hop.orports[0].addr, "1::2");
+ extend_info_t *multi_ipv6_hop[DEFAULT_ROUTE_LEN] = {&ipv6_hop,
+ &ipv6_hop,
+ &ipv6_hop};
+
+ extend_info_t ipv4_hop;
+ memset(&ipv4_hop, 0, sizeof(ipv4_hop));
+ tor_addr_from_ipv4h(&ipv4_hop.orports[0].addr, 0x20304050);
+ extend_info_t *multi_ipv4_hop[DEFAULT_ROUTE_LEN] = {&ipv4_hop,
+ &ipv4_hop,
+ &ipv4_hop};
+
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ MOCK(circuit_deliver_create_cell, mock_circuit_deliver_create_cell);
+ server = 0;
+ MOCK(server_mode, mock_server_mode);
+
+ /* Try a direct connection, and succeed on a client */
+ server = 0;
+ origin_circ = new_test_origin_circuit(false,
+ circ_start_time,
+ 1,
+ &single_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ /* Skip some of the multi-hop checks */
+ origin_circ->build_state->onehop_tunnel = 1;
+ /* This is a direct connection */
+ mock_circuit_deliver_create_cell_expect_direct = true;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ, 0);
+ /* The circuits are automatically freed by the circuitlist. */
+
+ /* Try a direct connection, and succeed on a server */
+ server = 1;
+ origin_circ = new_test_origin_circuit(false,
+ circ_start_time,
+ 1,
+ &single_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->build_state->onehop_tunnel = 1;
+ mock_circuit_deliver_create_cell_expect_direct = true;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ, 0);
+
+ /* Start capturing bugs */
+ setup_full_capture_of_logs(LOG_WARN);
+ tor_capture_bugs_(1);
+
+ /* Try an extend, but fail the client valid address family check */
+ server = 0;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_fakehop),
+ multi_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ /* Fix the state */
+ origin_circ->base_.state = 0;
+ /* This is an indirect connection */
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ /* Fail because the address family is invalid */
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("No supported address family found in extend_info.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, but fail the server valid address check */
+ server = 1;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_fakehop),
+ multi_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("No supported address family found in extend_info.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, but fail in the client code, with an IPv6 address */
+ server = 0;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv6_hop),
+ multi_ipv6_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("No supported address family found in extend_info.\n");
+ mock_clean_saved_logs();
+
+ /* Stop capturing bugs, but keep capturing logs */
+ tor_end_capture_bugs_();
+
+ /* Try an extend, pass the client IPv4 check, but fail later */
+ server = 0;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv4_hop),
+ multi_ipv4_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ /* Fail because the circuit data is invalid */
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("onion_skin_create failed.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, pass the server IPv4 check, but fail later */
+ server = 1;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv4_hop),
+ multi_ipv4_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("onion_skin_create failed.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, pass the server IPv6 check, but fail later */
+ server = 1;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv6_hop),
+ multi_ipv6_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("onion_skin_create failed.\n");
+ mock_clean_saved_logs();
+
+ /* Things we're not testing right now:
+ * - the addresses in the extend cell inside
+ * circuit_send_intermediate_onion_skin() matches the address in the
+ * supplied extend_info.
+ * - valid circuit data.
+ * - actually extending the circuit to each hop. */
+
+ done:
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ teardown_capture_of_logs();
+
+ UNMOCK(circuit_deliver_create_cell);
+ UNMOCK(server_mode);
+ server = 0;
+
+ /* The circuits are automatically freed by the circuitlist. */
+}
+
+/* Test the different cases in cpath_build_state_to_crn_flags(). */
+static void
+test_cpath_build_state_to_crn_flags(void *arg)
+{
+ (void)arg;
+
+ cpath_build_state_t state;
+ memset(&state, 0, sizeof(state));
+
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ 0);
+
+ memset(&state, 0, sizeof(state));
+ state.need_uptime = 1;
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_UPTIME);
+
+ memset(&state, 0, sizeof(state));
+ state.need_capacity = 1;
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_CAPACITY);
+
+ memset(&state, 0, sizeof(state));
+ state.need_capacity = 1;
+ state.need_uptime = 1;
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_CAPACITY | CRN_NEED_UPTIME);
+
+ /* Check that no other flags are handled */
+ memset(&state, 0xff, sizeof(state));
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_CAPACITY | CRN_NEED_UPTIME);
+
+ done:
+ ;
+}
+
+/* Test the different cases in cpath_build_state_to_crn_ipv6_extend_flag(). */
+static void
+test_cpath_build_state_to_crn_ipv6_extend_flag(void *arg)
+{
+ (void)arg;
+
+ cpath_build_state_t state;
+
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ tt_int_op(cpath_build_state_to_crn_ipv6_extend_flag(&state, 0), OP_EQ,
+ 0);
+
+ /* Pass the state flag check, but not the length check */
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ state.is_ipv6_selftest = 1;
+ tt_int_op(cpath_build_state_to_crn_ipv6_extend_flag(&state, 0), OP_EQ,
+ 0);
+
+ /* Pass the length check, but not the state flag check */
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ tt_int_op(
+ cpath_build_state_to_crn_ipv6_extend_flag(&state,
+ DEFAULT_ROUTE_LEN - 2),
+ OP_EQ, 0);
+
+ /* Pass both checks */
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ state.is_ipv6_selftest = 1;
+ tt_int_op(
+ cpath_build_state_to_crn_ipv6_extend_flag(&state,
+ DEFAULT_ROUTE_LEN - 2),
+ OP_EQ, CRN_INITIATE_IPV6_EXTEND);
+
+ /* Check that no other flags are handled */
+ memset(&state, 0xff, sizeof(state));
+ state.desired_path_len = INT_MAX;
+ tt_int_op(cpath_build_state_to_crn_ipv6_extend_flag(&state, INT_MAX), OP_EQ,
+ 0);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Start capturing bugs */
+ setup_full_capture_of_logs(LOG_INFO);
+ tor_capture_bugs_(1);
+
+ /* Now test the single hop circuit case */
+#define SINGLE_HOP_ROUTE_LEN 1
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = SINGLE_HOP_ROUTE_LEN;
+ state.is_ipv6_selftest = 1;
+ tt_int_op(
+ cpath_build_state_to_crn_ipv6_extend_flag(&state,
+ SINGLE_HOP_ROUTE_LEN - 2),
+ 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_(state->desired_path_len < 2))");
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ done:
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ teardown_capture_of_logs();
+}
+
+#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 }
+
+#define TEST_CPATH(name, flags) \
+ { #name, test_cpath_ ## 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,
- NULL, 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(extend_add_ip, 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),
+
+ TEST(origin_circuit_init, TT_FORK, NULL, NULL),
+ TEST_CIRCUIT(send_next_onion_skin, TT_FORK),
+ TEST_CPATH(build_state_to_crn_flags, 0),
+ TEST_CPATH(build_state_to_crn_ipv6_extend_flag, TT_FORK),
+
END_OF_TESTCASES
};
diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c
index 5cebdbeda0..63c4418f29 100644
--- a/src/test/test_circuitlist.c
+++ b/src/test/test_circuitlist.c
@@ -1,7 +1,7 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CIRCUITBUILD_PRIVATE
#define CIRCUITLIST_PRIVATE
#define HS_CIRCUITMAP_PRIVATE
@@ -136,7 +136,7 @@ test_clist_maps(void *arg)
channel_note_destroy_pending(ch2, 200);
channel_note_destroy_pending(ch2, 205);
channel_note_destroy_pending(ch1, 100);
- tt_assert(circuit_id_in_use_on_channel(205, ch2))
+ tt_assert(circuit_id_in_use_on_channel(205, ch2));
tt_assert(circuit_id_in_use_on_channel(200, ch2));
tt_assert(circuit_id_in_use_on_channel(100, ch1));
diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c
index a2b3e62fe8..d6e3300a30 100644
--- a/src/test/test_circuitmux.c
+++ b/src/test/test_circuitmux.c
@@ -1,33 +1,27 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CIRCUITMUX_PRIVATE
#define CIRCUITMUX_EWMA_PRIVATE
#define RELAY_PRIVATE
+
#include "core/or/or.h"
#include "core/or/channel.h"
#include "core/or/circuitmux.h"
#include "core/or/circuitmux_ewma.h"
+#include "core/or/destroy_cell_queue_st.h"
#include "core/or/relay.h"
#include "core/or/scheduler.h"
-#include "test/test.h"
-#include "core/or/destroy_cell_queue_st.h"
+#include "test/fakechans.h"
+#include "test/fakecircs.h"
+#include "test/test.h"
#include <math.h>
-/* XXXX duplicated function from test_circuitlist.c */
-static channel_t *
-new_fake_channel(void)
-{
- channel_t *chan = tor_malloc_zero(sizeof(channel_t));
- channel_init(chan);
- return chan;
-}
-
static int
-has_queued_writes(channel_t *c)
+mock_has_queued_writes_true(channel_t *c)
{
(void) c;
return 1;
@@ -44,16 +38,14 @@ test_cmux_destroy_cell_queue(void *arg)
packed_cell_t *pc = NULL;
destroy_cell_t *dc = NULL;
- scheduler_init();
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
(void) arg;
- cmux = circuitmux_alloc();
- tt_assert(cmux);
ch = new_fake_channel();
- circuitmux_set_policy(cmux, &ewma_policy);
- ch->has_queued_writes = has_queued_writes;
+ ch->has_queued_writes = mock_has_queued_writes_true;
ch->wide_circ_ids = 1;
+ cmux = ch->cmux;
circ = circuitmux_get_first_active_circuit(cmux, &cq);
tt_ptr_op(circ, OP_EQ, NULL);
@@ -78,10 +70,11 @@ test_cmux_destroy_cell_queue(void *arg)
tt_int_op(circuitmux_num_cells(cmux), OP_EQ, 2);
done:
- circuitmux_free(cmux);
- channel_free(ch);
+ free_fake_channel(ch);
packed_cell_free(pc);
tor_free(dc);
+
+ UNMOCK(scheduler_release_channel);
}
static void
@@ -125,9 +118,363 @@ test_cmux_compute_ticks(void *arg)
;
}
+static void
+test_cmux_allocate(void *arg)
+{
+ circuitmux_t *cmux = NULL;
+
+ (void) arg;
+
+ cmux = circuitmux_alloc();
+ tt_assert(cmux);
+ tt_assert(cmux->chanid_circid_map);
+ tt_int_op(HT_SIZE(cmux->chanid_circid_map), OP_EQ, 0);
+ tt_uint_op(cmux->n_circuits, OP_EQ, 0);
+ tt_uint_op(cmux->n_active_circuits, OP_EQ, 0);
+ tt_uint_op(cmux->n_cells, OP_EQ, 0);
+ tt_uint_op(cmux->last_cell_was_destroy, OP_EQ, 0);
+ tt_i64_op(cmux->destroy_ctr, OP_EQ, 0);
+ tt_ptr_op(cmux->policy, OP_EQ, NULL);
+ tt_ptr_op(cmux->policy_data, OP_EQ, NULL);
+
+ tt_assert(TOR_SIMPLEQ_EMPTY(&cmux->destroy_cell_queue.head));
+
+ done:
+ circuitmux_free(cmux);
+}
+
+static void
+test_cmux_attach_circuit(void *arg)
+{
+ circuit_t *circ = NULL;
+ or_circuit_t *orcirc = NULL;
+ channel_t *pchan = NULL, *nchan = NULL;
+ cell_direction_t cdir;
+ unsigned int n_cells;
+
+ (void) arg;
+
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+ circ = TO_CIRCUIT(orcirc);
+
+ /* While assigning a new circuit IDs, the circuitmux_attach_circuit() is
+ * called for a new channel on the circuit. This means, we should now have
+ * the created circuit attached on both the pchan and nchan cmux. */
+ tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 1);
+ tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 1);
+
+ /* There should be _no_ active circuit due to no queued cells. */
+ tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 0);
+ tt_uint_op(circuitmux_num_active_circuits(nchan->cmux), OP_EQ, 0);
+
+ /* Circuit should not be active on the cmux. */
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_active(nchan->cmux, circ), OP_EQ, 0);
+
+ /* Not active so no cells. */
+ n_cells = circuitmux_num_cells_for_circuit(pchan->cmux, circ);
+ tt_uint_op(n_cells, OP_EQ, 0);
+ n_cells = circuitmux_num_cells(pchan->cmux);
+ tt_uint_op(n_cells, OP_EQ, 0);
+ n_cells = circuitmux_num_cells_for_circuit(nchan->cmux, circ);
+ tt_uint_op(n_cells, OP_EQ, 0);
+ n_cells = circuitmux_num_cells(nchan->cmux);
+ tt_uint_op(n_cells, OP_EQ, 0);
+
+ /* So it should be attached :) */
+ tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 1);
+ tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 1);
+
+ /* Query the chanid<->circid map in the cmux subsystem with what we just
+ * created and validate the cell direction. */
+ cdir = circuitmux_attached_circuit_direction(pchan->cmux, circ);
+ tt_int_op(cdir, OP_EQ, CELL_DIRECTION_IN);
+ cdir = circuitmux_attached_circuit_direction(nchan->cmux, circ);
+ tt_int_op(cdir, OP_EQ, CELL_DIRECTION_OUT);
+
+ /*
+ * We'll activate->deactivate->activate to test all code paths of
+ * circuitmux_set_num_cells().
+ */
+
+ /* Activate circuit. */
+ circuitmux_set_num_cells(pchan->cmux, circ, 4);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
+
+ /* Deactivate. */
+ circuitmux_clear_num_cells(pchan->cmux, circ);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
+ tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 0);
+
+ /* Re-activate. */
+ circuitmux_set_num_cells(pchan->cmux, circ, 4);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
+
+ /* Once re-attached, it should become inactive because the circuit has no
+ * cells while the chanid<->circid object has some. The attach code will
+ * reset the count on the cmux for that circuit:
+ *
+ * if (chanid_circid_muxinfo_t->muxinfo.cell_count > 0 && cell_count == 0) {
+ */
+ circuitmux_attach_circuit(pchan->cmux, circ, CELL_DIRECTION_IN);
+ n_cells = circuitmux_num_cells_for_circuit(pchan->cmux, circ);
+ tt_uint_op(n_cells, OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
+ tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 0);
+
+ /* Lets queue a cell on the circuit now so it becomes active when
+ * re-attaching:
+ *
+ * else if (chanid_circid_muxinfo_t->muxinfo.cell_count == 0 &&
+ * cell_count > 0) {
+ */
+ orcirc->p_chan_cells.n = 1;
+ circuitmux_attach_circuit(pchan->cmux, circ, CELL_DIRECTION_IN);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
+
+ done:
+ free_fake_orcirc(orcirc);
+ free_fake_channel(pchan);
+ free_fake_channel(nchan);
+}
+
+static void
+test_cmux_detach_circuit(void *arg)
+{
+ circuit_t *circ = NULL;
+ or_circuit_t *orcirc = NULL;
+ channel_t *pchan = NULL, *nchan = NULL;
+
+ (void) arg;
+
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+ circ = TO_CIRCUIT(orcirc);
+
+ /* While assigning a new circuit IDs, the circuitmux_attach_circuit() is
+ * called for a new channel on the circuit. This means, we should now have
+ * the created circuit attached on both the pchan and nchan cmux. */
+ tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 1);
+ tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 1);
+ tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 1);
+ tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 1);
+
+ /* Now, detach the circuit from pchan and then nchan. */
+ circuitmux_detach_circuit(pchan->cmux, circ);
+ tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 0);
+ circuitmux_detach_circuit(nchan->cmux, circ);
+ tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 0);
+
+ done:
+ free_fake_orcirc(orcirc);
+ free_fake_channel(pchan);
+ free_fake_channel(nchan);
+}
+
+static void
+test_cmux_detach_all_circuits(void *arg)
+{
+ circuit_t *circ = NULL;
+ or_circuit_t *orcirc = NULL;
+ channel_t *pchan = NULL, *nchan = NULL;
+ smartlist_t *detached_out = smartlist_new();
+
+ (void) arg;
+
+ /* Channels need to be registered in order for the detach all circuit
+ * function to find them. */
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+ channel_register(pchan);
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+ channel_register(nchan);
+
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+ circ = TO_CIRCUIT(orcirc);
+
+ /* Just make sure it is attached. */
+ tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 1);
+ tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 1);
+ tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 1);
+ tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 1);
+
+ /* Queue some cells so we can test if the circuit becomes inactive on the
+ * cmux after the mass detach. */
+ circuitmux_set_num_cells(pchan->cmux, circ, 4);
+ circuitmux_set_num_cells(nchan->cmux, circ, 4);
+
+ /* Detach all on pchan and then nchan. */
+ circuitmux_detach_all_circuits(pchan->cmux, detached_out);
+ tt_uint_op(circuitmux_num_circuits(pchan->cmux), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_attached(pchan->cmux, circ), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
+ tt_int_op(smartlist_len(detached_out), OP_EQ, 1);
+ circuitmux_detach_all_circuits(nchan->cmux, NULL);
+ tt_uint_op(circuitmux_num_circuits(nchan->cmux), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_attached(nchan->cmux, circ), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_active(nchan->cmux, circ), OP_EQ, 0);
+
+ done:
+ smartlist_free(detached_out);
+ free_fake_orcirc(orcirc);
+ free_fake_channel(pchan);
+ free_fake_channel(nchan);
+}
+
+static void
+test_cmux_policy(void *arg)
+{
+ circuit_t *circ = NULL;
+ or_circuit_t *orcirc = NULL;
+ channel_t *pchan = NULL, *nchan = NULL;
+
+ (void) arg;
+
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+ channel_register(pchan);
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+ channel_register(nchan);
+
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+ circ = TO_CIRCUIT(orcirc);
+
+ /* Confirm we have the EWMA policy by default for new channels. */
+ tt_ptr_op(circuitmux_get_policy(pchan->cmux), OP_EQ, &ewma_policy);
+ tt_ptr_op(circuitmux_get_policy(nchan->cmux), OP_EQ, &ewma_policy);
+
+ /* Putting cell on the cmux means will make the notify policy code path to
+ * trigger. */
+ circuitmux_set_num_cells(pchan->cmux, circ, 4);
+
+ /* Clear it out. */
+ circuitmux_clear_policy(pchan->cmux);
+
+ /* Set back the EWMA policy. */
+ circuitmux_set_policy(pchan->cmux, &ewma_policy);
+
+ done:
+ free_fake_orcirc(orcirc);
+ free_fake_channel(pchan);
+ free_fake_channel(nchan);
+}
+
+static void
+test_cmux_xmit_cell(void *arg)
+{
+ circuit_t *circ = NULL;
+ or_circuit_t *orcirc = NULL;
+ channel_t *pchan = NULL, *nchan = NULL;
+
+ (void) arg;
+
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+ circ = TO_CIRCUIT(orcirc);
+
+ /* Queue 4 cells on the circuit. */
+ circuitmux_set_num_cells(pchan->cmux, circ, 4);
+ tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 4);
+ tt_uint_op(circuitmux_num_cells(pchan->cmux), OP_EQ, 4);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
+ tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 1);
+
+ /* Emit the first cell. Circuit should still be active. */
+ circuitmux_notify_xmit_cells(pchan->cmux, circ, 1);
+ tt_uint_op(circuitmux_num_cells(pchan->cmux), OP_EQ, 3);
+ tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 3);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 1);
+ tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 1);
+
+ /* Emit the last 3 cells. Circuit should become inactive. */
+ circuitmux_notify_xmit_cells(pchan->cmux, circ, 3);
+ tt_uint_op(circuitmux_num_cells(pchan->cmux), OP_EQ, 0);
+ tt_uint_op(circuitmux_num_cells_for_circuit(pchan->cmux, circ), OP_EQ, 0);
+ tt_int_op(circuitmux_is_circuit_active(pchan->cmux, circ), OP_EQ, 0);
+ tt_uint_op(circuitmux_num_active_circuits(pchan->cmux), OP_EQ, 0);
+
+ /* Queue a DESTROY cell. */
+ pchan->has_queued_writes = mock_has_queued_writes_true;
+ circuitmux_append_destroy_cell(pchan, pchan->cmux, orcirc->p_circ_id, 0);
+ tt_i64_op(pchan->cmux->destroy_ctr, OP_EQ, 1);
+ tt_int_op(pchan->cmux->destroy_cell_queue.n, OP_EQ, 1);
+ tt_i64_op(circuitmux_count_queued_destroy_cells(pchan, pchan->cmux),
+ OP_EQ, 1);
+
+ /* Emit the DESTROY cell. */
+ circuitmux_notify_xmit_destroy(pchan->cmux);
+ tt_i64_op(pchan->cmux->destroy_ctr, OP_EQ, 0);
+
+ done:
+ free_fake_orcirc(orcirc);
+ free_fake_channel(pchan);
+ free_fake_channel(nchan);
+}
+
+static void *
+cmux_setup_test(const struct testcase_t *tc)
+{
+ static int whatever;
+
+ (void) tc;
+
+ cell_ewma_initialize_ticks();
+ return &whatever;
+}
+
+static int
+cmux_cleanup_test(const struct testcase_t *tc, void *ptr)
+{
+ (void) tc;
+ (void) ptr;
+
+ circuitmux_ewma_free_all();
+
+ return 1;
+}
+
+static struct testcase_setup_t cmux_test_setup = {
+ .setup_fn = cmux_setup_test,
+ .cleanup_fn = cmux_cleanup_test,
+};
+
+#define TEST_CMUX(name) \
+ { #name, test_cmux_##name, TT_FORK, &cmux_test_setup, NULL }
+
struct testcase_t circuitmux_tests[] = {
- { "destroy_cell_queue", test_cmux_destroy_cell_queue, TT_FORK, NULL, NULL },
- { "compute_ticks", test_cmux_compute_ticks, TT_FORK, NULL, NULL },
+ /* Test circuitmux_t object */
+ TEST_CMUX(allocate),
+ TEST_CMUX(attach_circuit),
+ TEST_CMUX(detach_circuit),
+ TEST_CMUX(detach_all_circuits),
+ TEST_CMUX(policy),
+ TEST_CMUX(xmit_cell),
+
+ /* Misc. */
+ TEST_CMUX(compute_ticks),
+ TEST_CMUX(destroy_cell_queue),
+
END_OF_TESTCASES
};
-
diff --git a/src/test/test_circuitmux_ewma.c b/src/test/test_circuitmux_ewma.c
new file mode 100644
index 0000000000..27601e0c7d
--- /dev/null
+++ b/src/test/test_circuitmux_ewma.c
@@ -0,0 +1,228 @@
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CIRCUITMUX_PRIVATE
+#define CIRCUITMUX_EWMA_PRIVATE
+
+#include "core/or/or.h"
+#include "core/or/circuitmux.h"
+#include "core/or/circuitmux_ewma.h"
+
+#include "test/fakechans.h"
+#include "test/fakecircs.h"
+#include "test/test.h"
+
+static void
+test_cmux_ewma_active_circuit(void *arg)
+{
+ circuitmux_t cmux; /* garbage */
+ circuitmux_policy_data_t *pol_data = NULL;
+ circuit_t circ; /* garbage */
+ circuitmux_policy_circ_data_t *circ_data = NULL;
+
+ (void) arg;
+
+ pol_data = ewma_policy.alloc_cmux_data(&cmux);
+ tt_assert(pol_data);
+ circ_data = ewma_policy.alloc_circ_data(&cmux, pol_data, &circ,
+ CELL_DIRECTION_OUT, 42);
+ tt_assert(circ_data);
+
+ /* Get EWMA specific objects. */
+
+ /* Make circuit active. */
+ ewma_policy.notify_circ_active(&cmux, pol_data, &circ, circ_data);
+
+ circuit_t *entry = ewma_policy.pick_active_circuit(&cmux, pol_data);
+ tt_mem_op(entry, OP_EQ, &circ, sizeof(circ));
+
+ done:
+ ewma_policy.free_circ_data(&cmux, pol_data, &circ, circ_data);
+ ewma_policy.free_cmux_data(&cmux, pol_data);
+}
+
+static void
+test_cmux_ewma_xmit_cell(void *arg)
+{
+ circuitmux_t cmux; /* garbage */
+ circuitmux_policy_data_t *pol_data = NULL;
+ circuit_t circ; /* garbage */
+ circuitmux_policy_circ_data_t *circ_data = NULL;
+ ewma_policy_data_t *ewma_pol_data;
+ ewma_policy_circ_data_t *ewma_data;
+ double old_cell_count;
+
+ (void) arg;
+
+ pol_data = ewma_policy.alloc_cmux_data(&cmux);
+ tt_assert(pol_data);
+ circ_data = ewma_policy.alloc_circ_data(&cmux, pol_data, &circ,
+ CELL_DIRECTION_OUT, 42);
+ tt_assert(circ_data);
+ ewma_pol_data = TO_EWMA_POL_DATA(pol_data);
+ ewma_data = TO_EWMA_POL_CIRC_DATA(circ_data);
+
+ /* Make circuit active. */
+ ewma_policy.notify_circ_active(&cmux, pol_data, &circ, circ_data);
+
+ /* Move back in time the last time we calibrated so we scale the active
+ * circuit when emitting a cell. */
+ ewma_pol_data->active_circuit_pqueue_last_recalibrated -= 100;
+ ewma_data->cell_ewma.last_adjusted_tick =
+ ewma_pol_data->active_circuit_pqueue_last_recalibrated;
+
+ /* Grab old cell count. */
+ old_cell_count = ewma_data->cell_ewma.cell_count;
+
+ ewma_policy.notify_xmit_cells(&cmux, pol_data, &circ, circ_data, 1);
+
+ /* Our old cell count should be lower to what we have since we just emitted
+ * a cell and thus we scale. */
+ tt_double_op(old_cell_count, OP_LT, ewma_data->cell_ewma.cell_count);
+
+ done:
+ ewma_policy.free_circ_data(&cmux, pol_data, &circ, circ_data);
+ ewma_policy.free_cmux_data(&cmux, pol_data);
+}
+
+static void
+test_cmux_ewma_notify_circ(void *arg)
+{
+ circuitmux_t cmux; /* garbage */
+ circuitmux_policy_data_t *pol_data = NULL;
+ circuit_t circ; /* garbage */
+ circuitmux_policy_circ_data_t *circ_data = NULL;
+ const ewma_policy_data_t *ewma_pol_data;
+
+ (void) arg;
+
+ pol_data = ewma_policy.alloc_cmux_data(&cmux);
+ tt_assert(pol_data);
+ circ_data = ewma_policy.alloc_circ_data(&cmux, pol_data, &circ,
+ CELL_DIRECTION_OUT, 42);
+ tt_assert(circ_data);
+
+ /* Currently, notify_circ_active() ignores cmux and circ. They can not be
+ * NULL so it is fine to pass garbage. */
+ ewma_policy.notify_circ_active(&cmux, pol_data, &circ, circ_data);
+
+ /* We should have an active circuit in the queue so its EWMA value can be
+ * tracked. */
+ ewma_pol_data = TO_EWMA_POL_DATA(pol_data);
+ tt_int_op(smartlist_len(ewma_pol_data->active_circuit_pqueue), OP_EQ, 1);
+ tt_uint_op(ewma_pol_data->active_circuit_pqueue_last_recalibrated, OP_NE, 0);
+
+ ewma_policy.notify_circ_inactive(&cmux, pol_data, &circ, circ_data);
+ /* Should be removed from the active queue. */
+ ewma_pol_data = TO_EWMA_POL_DATA(pol_data);
+ tt_int_op(smartlist_len(ewma_pol_data->active_circuit_pqueue), OP_EQ, 0);
+ tt_uint_op(ewma_pol_data->active_circuit_pqueue_last_recalibrated, OP_NE, 0);
+
+ done:
+ ewma_policy.free_circ_data(&cmux, pol_data, &circ, circ_data);
+ ewma_policy.free_cmux_data(&cmux, pol_data);
+}
+
+static void
+test_cmux_ewma_policy_circ_data(void *arg)
+{
+ circuitmux_t cmux; /* garbage */
+ circuitmux_policy_data_t pol_data; /* garbage */
+ circuit_t circ; /* garbage */
+ circuitmux_policy_circ_data_t *circ_data = NULL;
+ const ewma_policy_circ_data_t *ewma_data;
+
+ (void) arg;
+
+ /* Currently, alloc_circ_data() ignores every parameter _except_ the cell
+ * direction so it is OK to pass garbage. They can not be NULL. */
+ circ_data = ewma_policy.alloc_circ_data(&cmux, &pol_data, &circ,
+ CELL_DIRECTION_OUT, 42);
+ tt_assert(circ_data);
+ tt_uint_op(circ_data->magic, OP_EQ, EWMA_POL_CIRC_DATA_MAGIC);
+
+ ewma_data = TO_EWMA_POL_CIRC_DATA(circ_data);
+ tt_mem_op(ewma_data->circ, OP_EQ, &circ, sizeof(circuit_t));
+ tt_double_op(ewma_data->cell_ewma.cell_count, OP_LE, 0.0);
+ tt_int_op(ewma_data->cell_ewma.heap_index, OP_EQ, -1);
+ tt_uint_op(ewma_data->cell_ewma.is_for_p_chan, OP_EQ, 0);
+ ewma_policy.free_circ_data(&cmux, &pol_data, &circ, circ_data);
+
+ circ_data = ewma_policy.alloc_circ_data(&cmux, &pol_data, &circ,
+ CELL_DIRECTION_IN, 42);
+ tt_assert(circ_data);
+ tt_uint_op(circ_data->magic, OP_EQ, EWMA_POL_CIRC_DATA_MAGIC);
+
+ ewma_data = TO_EWMA_POL_CIRC_DATA(circ_data);
+ tt_mem_op(ewma_data->circ, OP_EQ, &circ, sizeof(circuit_t));
+ tt_double_op(ewma_data->cell_ewma.cell_count, OP_LE, 0.0);
+ tt_int_op(ewma_data->cell_ewma.heap_index, OP_EQ, -1);
+ tt_uint_op(ewma_data->cell_ewma.is_for_p_chan, OP_EQ, 1);
+
+ done:
+ ewma_policy.free_circ_data(&cmux, &pol_data, &circ, circ_data);
+}
+
+static void
+test_cmux_ewma_policy_data(void *arg)
+{
+ circuitmux_t cmux; /* garbage. */
+ circuitmux_policy_data_t *pol_data = NULL;
+ const ewma_policy_data_t *ewma_pol_data;
+
+ (void) arg;
+
+ pol_data = ewma_policy.alloc_cmux_data(&cmux);
+ tt_assert(pol_data);
+ tt_uint_op(pol_data->magic, OP_EQ, EWMA_POL_DATA_MAGIC);
+
+ /* Test EWMA object. */
+ ewma_pol_data = TO_EWMA_POL_DATA(pol_data);
+ tt_assert(ewma_pol_data->active_circuit_pqueue);
+ tt_uint_op(ewma_pol_data->active_circuit_pqueue_last_recalibrated, OP_NE, 0);
+
+ done:
+ ewma_policy.free_cmux_data(&cmux, pol_data);
+}
+
+static void *
+cmux_ewma_setup_test(const struct testcase_t *tc)
+{
+ static int whatever;
+
+ (void) tc;
+
+ cell_ewma_initialize_ticks();
+ cmux_ewma_set_options(NULL, NULL);
+
+ return &whatever;
+}
+
+static int
+cmux_ewma_cleanup_test(const struct testcase_t *tc, void *ptr)
+{
+ (void) tc;
+ (void) ptr;
+
+ circuitmux_ewma_free_all();
+
+ return 1;
+}
+
+static struct testcase_setup_t cmux_ewma_test_setup = {
+ .setup_fn = cmux_ewma_setup_test,
+ .cleanup_fn = cmux_ewma_cleanup_test,
+};
+
+#define TEST_CMUX_EWMA(name) \
+ { #name, test_cmux_ewma_##name, TT_FORK, &cmux_ewma_test_setup, NULL }
+
+struct testcase_t circuitmux_ewma_tests[] = {
+ TEST_CMUX_EWMA(active_circuit),
+ TEST_CMUX_EWMA(policy_data),
+ TEST_CMUX_EWMA(policy_circ_data),
+ TEST_CMUX_EWMA(notify_circ),
+ TEST_CMUX_EWMA(xmit_cell),
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c
new file mode 100644
index 0000000000..86baf54f40
--- /dev/null
+++ b/src/test/test_circuitpadding.c
@@ -0,0 +1,3148 @@
+#define CHANNEL_OBJECT_PRIVATE
+#define TOR_TIMERS_PRIVATE
+#define CIRCUITPADDING_PRIVATE
+#define CIRCUITPADDING_MACHINES_PRIVATE
+#define NETWORKSTATUS_PRIVATE
+#define CRYPT_PATH_PRIVATE
+#define RELAY_PRIVATE
+
+#include "core/or/or.h"
+#include "test/test.h"
+#include "test/log_test_helpers.h"
+#include "lib/testsupport/testsupport.h"
+#include "core/or/connection_or.h"
+#include "core/or/channel.h"
+#include "core/or/channeltls.h"
+#include "core/or/crypt_path.h"
+#include <event.h>
+#include "lib/evloop/compat_libevent.h"
+#include "lib/time/compat_time.h"
+#include "lib/defs/time.h"
+#include "core/or/relay.h"
+#include "core/or/circuitlist.h"
+#include "core/or/circuitbuild.h"
+#include "core/or/circuitpadding.h"
+#include "core/or/circuitpadding_machines.h"
+#include "core/or/extendinfo.h"
+#include "core/mainloop/netstatus.h"
+#include "core/crypto/relay_crypto.h"
+#include "core/or/protover.h"
+#include "feature/nodelist/nodelist.h"
+#include "app/config/config.h"
+
+#include "feature/nodelist/routerstatus_st.h"
+#include "feature/nodelist/networkstatus_st.h"
+#include "feature/nodelist/node_st.h"
+#include "core/or/cell_st.h"
+#include "core/or/crypt_path_st.h"
+#include "core/or/or_circuit_st.h"
+#include "core/or/origin_circuit_st.h"
+
+#include "test/fakecircs.h"
+#include "test/rng_test_helpers.h"
+
+/* Start our monotime mocking at 1 second past whatever monotime_init()
+ * thought the actual wall clock time was, for platforms with bad resolution
+ * and weird timevalues during monotime_init() before mocking. */
+#define MONOTIME_MOCK_START (monotime_absolute_nsec()+\
+ TOR_NSEC_PER_USEC*TOR_USEC_PER_SEC)
+
+extern smartlist_t *connection_array;
+void circuit_expire_old_circuits_clientside(void);
+
+circid_t get_unique_circ_id_by_chan(channel_t *chan);
+void helper_create_basic_machine(void);
+static void helper_create_conditional_machines(void);
+
+channel_t *new_fake_channel(void);
+void test_circuitpadding_negotiation(void *arg);
+void test_circuitpadding_wronghop(void *arg);
+void test_circuitpadding_conditions(void *arg);
+
+void test_circuitpadding_serialize(void *arg);
+void test_circuitpadding_rtt(void *arg);
+void test_circuitpadding_tokens(void *arg);
+void test_circuitpadding_state_length(void *arg);
+
+static void
+simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay,
+ int padding);
+void free_fake_origin_circuit(origin_circuit_t *circ);
+
+static int deliver_negotiated = 1;
+static int64_t curr_mocked_time;
+
+static node_t padding_node;
+static node_t non_padding_node;
+
+static channel_t dummy_channel;
+static circpad_machine_spec_t circ_client_machine;
+
+static void
+timers_advance_and_run(int64_t msec_update)
+{
+ curr_mocked_time += msec_update*TOR_NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(curr_mocked_time);
+ monotime_set_mock_time_nsec(curr_mocked_time);
+ timers_run_pending();
+}
+
+static void
+nodes_init(void)
+{
+ padding_node.rs = tor_malloc_zero(sizeof(routerstatus_t));
+ padding_node.rs->pv.supports_hs_setup_padding = 1;
+
+ non_padding_node.rs = tor_malloc_zero(sizeof(routerstatus_t));
+ non_padding_node.rs->pv.supports_hs_setup_padding = 0;
+}
+
+static void
+nodes_free(void)
+{
+ tor_free(padding_node.rs);
+
+ tor_free(non_padding_node.rs);
+}
+
+static const node_t *
+node_get_by_id_mock(const char *identity_digest)
+{
+ if (identity_digest[0] == 1) {
+ return &padding_node;
+ } else if (identity_digest[0] == 0) {
+ return &non_padding_node;
+ }
+
+ return NULL;
+}
+
+static const node_t *
+circuit_get_nth_node_mock(origin_circuit_t *circ, int hop)
+{
+ (void) circ;
+ (void) hop;
+
+ return &padding_node;
+}
+
+void
+free_fake_origin_circuit(origin_circuit_t *circ)
+{
+ circpad_circuit_free_all_machineinfos(TO_CIRCUIT(circ));
+ circuit_clear_cpath(circ);
+ tor_free(circ);
+}
+
+void dummy_nop_timer(void);
+
+//static int dont_stop_libevent = 0;
+
+static circuit_t *client_side;
+static circuit_t *relay_side;
+
+static int n_client_cells = 0;
+static int n_relay_cells = 0;
+
+static int
+circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ,
+ cell_direction_t cell_direction,
+ crypt_path_t *layer_hint, streamid_t on_stream,
+ const char *filename, int lineno);
+
+static void
+circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction);
+
+static void
+circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction)
+{
+ (void)cmux;
+ (void)circ;
+ (void)direction;
+
+ return;
+}
+
+static int
+circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ,
+ cell_direction_t cell_direction,
+ crypt_path_t *layer_hint, streamid_t on_stream,
+ const char *filename, int lineno)
+{
+ (void)cell; (void)on_stream; (void)filename; (void)lineno;
+
+ if (circ == client_side) {
+ if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATE) {
+ // Deliver to relay
+ circpad_handle_padding_negotiate(relay_side, cell);
+ } else {
+
+ int is_target_hop = circpad_padding_is_from_expected_hop(circ,
+ layer_hint);
+ tt_int_op(cell_direction, OP_EQ, CELL_DIRECTION_OUT);
+ tt_int_op(is_target_hop, OP_EQ, 1);
+
+ // No need to pretend a padding cell was sent: This event is
+ // now emitted internally when the circuitpadding code sends them.
+ //circpad_cell_event_padding_sent(client_side);
+
+ // Receive padding cell at middle
+ circpad_deliver_recognized_relay_cell_events(relay_side,
+ cell->payload[0], NULL);
+ }
+ n_client_cells++;
+ } else if (circ == relay_side) {
+ tt_int_op(cell_direction, OP_EQ, CELL_DIRECTION_IN);
+
+ if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATED) {
+ // XXX: blah need right layer_hint..
+ if (deliver_negotiated)
+ circpad_handle_padding_negotiated(client_side, cell,
+ TO_ORIGIN_CIRCUIT(client_side)
+ ->cpath->next);
+ } else if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATE) {
+ circpad_handle_padding_negotiate(client_side, cell);
+ } else {
+ // No need to pretend a padding cell was sent: This event is
+ // now emitted internally when the circuitpadding code sends them.
+ //circpad_cell_event_padding_sent(relay_side);
+
+ // Receive padding cell at client
+ circpad_deliver_recognized_relay_cell_events(client_side,
+ cell->payload[0],
+ TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
+ }
+
+ n_relay_cells++;
+ }
+
+ done:
+ timers_advance_and_run(1);
+ return 0;
+}
+
+// Test reading and writing padding to strings (or options_t + consensus)
+void
+test_circuitpadding_serialize(void *arg)
+{
+ (void)arg;
+}
+
+static signed_error_t
+circpad_send_command_to_hop_mock(origin_circuit_t *circ, uint8_t hopnum,
+ uint8_t relay_command, const uint8_t *payload,
+ ssize_t payload_len)
+{
+ (void) circ;
+ (void) hopnum;
+ (void) relay_command;
+ (void) payload;
+ (void) payload_len;
+ return 0;
+}
+
+void
+test_circuitpadding_rtt(void *arg)
+{
+ /* Test Plan:
+ *
+ * 1. Test RTT measurement server side
+ * a. test usage of measured RTT
+ * 2. Test termination of RTT measurement
+ * a. test non-update of RTT
+ * 3. Test client side circuit and non-application of RTT..
+ */
+ circpad_delay_t rtt_estimate;
+ int64_t actual_mocked_monotime_start;
+ (void)arg;
+
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+ MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
+ testing_enable_reproducible_rng();
+
+ dummy_channel.cmux = circuitmux_alloc();
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ actual_mocked_monotime_start = MONOTIME_MOCK_START;
+ monotime_set_mock_time_nsec(actual_mocked_monotime_start);
+ monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
+ curr_mocked_time = actual_mocked_monotime_start;
+
+ timers_initialize();
+ circpad_machines_init();
+ helper_create_basic_machine();
+
+ MOCK(circuit_package_relay_cell,
+ circuit_package_relay_cell_mock);
+
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side,
+ 0);
+
+ relay_side->padding_machine[0] = &circ_client_machine;
+ relay_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side,0);
+
+ /* Test 1: Test measuring RTT */
+ circpad_cell_event_nonpadding_received(relay_side);
+ tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0);
+
+ timers_advance_and_run(20);
+
+ circpad_cell_event_nonpadding_sent(relay_side);
+ tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
+
+ tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_GE, 19000);
+ tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_LE, 30000);
+ tt_int_op(circpad_histogram_bin_to_usec(relay_side->padding_info[0], 0),
+ OP_EQ,
+ relay_side->padding_info[0]->rtt_estimate_usec+
+ circpad_machine_current_state(
+ relay_side->padding_info[0])->histogram_edges[0]);
+
+ circpad_cell_event_nonpadding_received(relay_side);
+ circpad_cell_event_nonpadding_received(relay_side);
+ tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0);
+ timers_advance_and_run(20);
+ circpad_cell_event_nonpadding_sent(relay_side);
+ circpad_cell_event_nonpadding_sent(relay_side);
+ tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
+
+ tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_GE, 20000);
+ tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_LE, 21000);
+ tt_int_op(circpad_histogram_bin_to_usec(relay_side->padding_info[0], 0),
+ OP_EQ,
+ relay_side->padding_info[0]->rtt_estimate_usec+
+ circpad_machine_current_state(
+ relay_side->padding_info[0])->histogram_edges[0]);
+
+ /* Test 2: Termination of RTT measurement (from the previous test) */
+ tt_int_op(relay_side->padding_info[0]->stop_rtt_update, OP_EQ, 1);
+ rtt_estimate = relay_side->padding_info[0]->rtt_estimate_usec;
+
+ circpad_cell_event_nonpadding_received(relay_side);
+ timers_advance_and_run(4);
+ circpad_cell_event_nonpadding_sent(relay_side);
+
+ tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_EQ,
+ rtt_estimate);
+ tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
+ tt_int_op(relay_side->padding_info[0]->stop_rtt_update, OP_EQ, 1);
+ tt_int_op(circpad_histogram_bin_to_usec(relay_side->padding_info[0], 0),
+ OP_EQ,
+ relay_side->padding_info[0]->rtt_estimate_usec+
+ circpad_machine_current_state(
+ relay_side->padding_info[0])->histogram_edges[0]);
+
+ /* Test 3: Make sure client side machine properly ignores RTT */
+ circpad_cell_event_nonpadding_received(client_side);
+ tt_u64_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
+
+ timers_advance_and_run(20);
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_u64_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
+
+ tt_int_op(client_side->padding_info[0]->rtt_estimate_usec, OP_EQ, 0);
+ tt_int_op(circpad_histogram_bin_to_usec(client_side->padding_info[0], 0),
+ OP_NE, client_side->padding_info[0]->rtt_estimate_usec);
+ tt_int_op(circpad_histogram_bin_to_usec(client_side->padding_info[0], 0),
+ OP_EQ,
+ circpad_machine_current_state(
+ client_side->padding_info[0])->histogram_edges[0]);
+ done:
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+ circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
+ circuitmux_free(dummy_channel.cmux);
+ timers_shutdown();
+ monotime_disable_test_mocking();
+ UNMOCK(circuit_package_relay_cell);
+ UNMOCK(circuitmux_attach_circuit);
+ tor_free(circ_client_machine.states);
+ testing_disable_reproducible_rng();
+
+ return;
+}
+
+void
+helper_create_basic_machine(void)
+{
+ /* Start, burst */
+ circpad_machine_states_init(&circ_client_machine, 2);
+
+ circ_client_machine.name = "basic";
+
+ circ_client_machine.states[CIRCPAD_STATE_START].
+ next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_BURST;
+ circ_client_machine.states[CIRCPAD_STATE_START].use_rtt_estimate = 1;
+
+ circ_client_machine.states[CIRCPAD_STATE_BURST].
+ next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_BURST;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].
+ next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_BURST;
+
+ circ_client_machine.states[CIRCPAD_STATE_BURST].
+ next_state[CIRCPAD_EVENT_NONPADDING_SENT] = CIRCPAD_STATE_CANCEL;
+
+ circ_client_machine.states[CIRCPAD_STATE_BURST].token_removal =
+ CIRCPAD_TOKEN_REMOVAL_HIGHER;
+
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_len = 5;
+
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 500;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 2500;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 5000;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[3] = 10000;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[4] = 20000;
+
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[0] = 1;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[1] = 0;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[2] = 2;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[3] = 2;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[4] = 2;
+
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_total_tokens = 7;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].use_rtt_estimate = 1;
+
+ return;
+}
+
+#define BIG_HISTOGRAM_LEN 10
+
+/** Setup a machine with a big histogram */
+static void
+helper_create_machine_with_big_histogram(circpad_removal_t removal_strategy)
+{
+ const int tokens_per_bin = 2;
+
+ /* Start, burst */
+ circpad_machine_states_init(&circ_client_machine, 2);
+
+ circpad_state_t *burst_state =
+ &circ_client_machine.states[CIRCPAD_STATE_BURST];
+
+ circ_client_machine.states[CIRCPAD_STATE_START].
+ next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_BURST;
+
+ burst_state->next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_BURST;
+ burst_state->next_state[CIRCPAD_EVENT_NONPADDING_RECV] =CIRCPAD_STATE_BURST;
+
+ burst_state->next_state[CIRCPAD_EVENT_NONPADDING_SENT] =CIRCPAD_STATE_CANCEL;
+
+ burst_state->token_removal = CIRCPAD_TOKEN_REMOVAL_HIGHER;
+
+ burst_state->histogram_len = BIG_HISTOGRAM_LEN;
+
+ int n_tokens = 0;
+ int i;
+ for (i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
+ burst_state->histogram[i] = tokens_per_bin;
+ n_tokens += tokens_per_bin;
+ }
+
+ burst_state->histogram_edges[0] = 0;
+ burst_state->histogram_edges[1] = 1;
+ burst_state->histogram_edges[2] = 7;
+ burst_state->histogram_edges[3] = 15;
+ burst_state->histogram_edges[4] = 31;
+ burst_state->histogram_edges[5] = 62;
+ burst_state->histogram_edges[6] = 125;
+ burst_state->histogram_edges[7] = 250;
+ burst_state->histogram_edges[8] = 500;
+ burst_state->histogram_edges[9] = 1000;
+
+ burst_state->histogram_total_tokens = n_tokens;
+ burst_state->length_dist.type = CIRCPAD_DIST_UNIFORM;
+ burst_state->length_dist.param1 = n_tokens;
+ burst_state->length_dist.param2 = n_tokens;
+ burst_state->max_length = n_tokens;
+ burst_state->length_includes_nonpadding = 1;
+ burst_state->use_rtt_estimate = 0;
+ burst_state->token_removal = removal_strategy;
+}
+
+static circpad_decision_t
+circpad_machine_schedule_padding_mock(circpad_machine_runtime_t *mi)
+{
+ (void)mi;
+ return 0;
+}
+
+static uint64_t
+mock_monotime_absolute_usec(void)
+{
+ return 100;
+}
+
+/** Test higher token removal strategy by bin */
+static void
+test_circuitpadding_token_removal_higher(void *arg)
+{
+ circpad_machine_runtime_t *mi;
+ (void)arg;
+
+ /* Mock it up */
+ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
+ MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+ testing_enable_reproducible_rng();
+
+ /* Setup test environment (time etc.) */
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ monotime_enable_test_mocking();
+
+ /* Create test machine */
+ helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_HIGHER);
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(client_side, 0);
+
+ /* move the machine to the right state */
+ circpad_cell_event_nonpadding_received(client_side);
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+
+ /* Get the machine and setup tokens */
+ mi = client_side->padding_info[0];
+ tt_assert(mi);
+
+ /*************************************************************************/
+
+ uint64_t current_time = monotime_absolute_usec();
+
+ /* Test left boundaries of each histogram bin: */
+ const circpad_delay_t bin_left_bounds[] =
+ {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
+ for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
+ tt_uint_op(bin_left_bounds[i], OP_EQ,
+ circpad_histogram_bin_to_usec(mi, i));
+ }
+
+ /* Test right boundaries of each histogram bin: */
+ const circpad_delay_t bin_right_bounds[] =
+ {0, 6, 14, 30, 61, 124, 249, 499, 999, CIRCPAD_DELAY_INFINITE-1};
+ for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
+ tt_uint_op(bin_right_bounds[i], OP_EQ,
+ histogram_get_bin_upper_bound(mi, i));
+ }
+
+ /* Check that all bins have two tokens right now */
+ for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
+ tt_int_op(mi->histogram[i], OP_EQ, 2);
+ }
+
+ /* This is the right order to remove tokens from this histogram. That is, we
+ * first remove tokens from the 4th bin since 57 usec is nearest to the 4th
+ * bin midpoint (31 + (62-31)/2 == 46). Then we remove from the 3rd bin for
+ * the same reason, then from the 5th, etc. */
+ const int bin_removal_order[] = {4, 5, 6, 7, 8};
+ unsigned i;
+
+ /* Remove all tokens from all bins apart from the infinity bin */
+ for (i = 0; i < sizeof(bin_removal_order)/sizeof(int) ; i++) {
+ int bin_to_remove = bin_removal_order[i];
+ log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
+ i, bin_to_remove);
+
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
+
+ mi->padding_scheduled_at_usec = current_time - 57;
+ circpad_cell_event_nonpadding_sent(client_side);
+
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
+
+ mi->padding_scheduled_at_usec = current_time - 57;
+ circpad_cell_event_nonpadding_sent(client_side);
+
+ /* Test that we cleaned out this bin. Don't do this in the case of the last
+ bin since the tokens will get refilled */
+ if (i != BIG_HISTOGRAM_LEN - 2) {
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
+ }
+ }
+
+ /* Check that all lower bins are not touched */
+ for (i=0; i < 4 ; i++) {
+ tt_int_op(mi->histogram[i], OP_EQ, 2);
+ }
+
+ /* Test below the lowest bin, for coverage */
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100;
+ mi->padding_scheduled_at_usec = current_time;
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_int_op(mi->histogram[0], OP_EQ, 1);
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ monotime_disable_test_mocking();
+ tor_free(circ_client_machine.states);
+ testing_disable_reproducible_rng();
+}
+
+/** Test lower token removal strategy by bin */
+static void
+test_circuitpadding_token_removal_lower(void *arg)
+{
+ circpad_machine_runtime_t *mi;
+ (void)arg;
+
+ /* Mock it up */
+ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
+ MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+ testing_enable_reproducible_rng();
+
+ /* Setup test environment (time etc.) */
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ monotime_enable_test_mocking();
+
+ /* Create test machine */
+ helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_LOWER);
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(client_side, 0);
+
+ /* move the machine to the right state */
+ circpad_cell_event_nonpadding_received(client_side);
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+
+ /* Get the machine and setup tokens */
+ mi = client_side->padding_info[0];
+ tt_assert(mi);
+
+ /*************************************************************************/
+
+ uint64_t current_time = monotime_absolute_usec();
+
+ /* Test left boundaries of each histogram bin: */
+ const circpad_delay_t bin_left_bounds[] =
+ {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
+ for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
+ tt_uint_op(bin_left_bounds[i], OP_EQ,
+ circpad_histogram_bin_to_usec(mi, i));
+ }
+
+ /* Check that all bins have two tokens right now */
+ for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
+ tt_int_op(mi->histogram[i], OP_EQ, 2);
+ }
+
+ /* This is the right order to remove tokens from this histogram. That is, we
+ * first remove tokens from the 4th bin since 57 usec is nearest to the 4th
+ * bin midpoint (31 + (62-31)/2 == 46). Then we remove from the 3rd bin for
+ * the same reason, then from the 5th, etc. */
+ const int bin_removal_order[] = {4, 3, 2, 1, 0};
+ unsigned i;
+
+ /* Remove all tokens from all bins apart from the infinity bin */
+ for (i = 0; i < sizeof(bin_removal_order)/sizeof(int) ; i++) {
+ int bin_to_remove = bin_removal_order[i];
+ log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
+ i, bin_to_remove);
+
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
+
+ mi->padding_scheduled_at_usec = current_time - 57;
+ circpad_cell_event_nonpadding_sent(client_side);
+
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
+
+ mi->padding_scheduled_at_usec = current_time - 57;
+ circpad_cell_event_nonpadding_sent(client_side);
+
+ /* Test that we cleaned out this bin. Don't do this in the case of the last
+ bin since the tokens will get refilled */
+ if (i != BIG_HISTOGRAM_LEN - 2) {
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
+ }
+ }
+
+ /* Check that all higher bins are untouched */
+ for (i = 5; i < BIG_HISTOGRAM_LEN ; i++) {
+ tt_int_op(mi->histogram[i], OP_EQ, 2);
+ }
+
+ /* Test above the highest bin, for coverage */
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+ circ_client_machine.states[CIRCPAD_STATE_BURST].
+ histogram_edges[BIG_HISTOGRAM_LEN-2] = 100;
+ mi->padding_scheduled_at_usec = current_time - 29202;
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1);
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ monotime_disable_test_mocking();
+ tor_free(circ_client_machine.states);
+ testing_disable_reproducible_rng();
+}
+
+/** Test closest token removal strategy by bin */
+static void
+test_circuitpadding_closest_token_removal(void *arg)
+{
+ circpad_machine_runtime_t *mi;
+ (void)arg;
+
+ /* Mock it up */
+ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
+ MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+ testing_enable_reproducible_rng();
+
+ /* Setup test environment (time etc.) */
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ monotime_enable_test_mocking();
+
+ /* Create test machine */
+ helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_CLOSEST);
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(client_side, 0);
+
+ /* move the machine to the right state */
+ circpad_cell_event_nonpadding_received(client_side);
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+
+ /* Get the machine and setup tokens */
+ mi = client_side->padding_info[0];
+ tt_assert(mi);
+
+ /*************************************************************************/
+
+ uint64_t current_time = monotime_absolute_usec();
+
+ /* Test left boundaries of each histogram bin: */
+ const circpad_delay_t bin_left_bounds[] =
+ {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
+ for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
+ tt_uint_op(bin_left_bounds[i], OP_EQ,
+ circpad_histogram_bin_to_usec(mi, i));
+ }
+
+ /* Check that all bins have two tokens right now */
+ for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
+ tt_int_op(mi->histogram[i], OP_EQ, 2);
+ }
+
+ /* This is the right order to remove tokens from this histogram. That is, we
+ * first remove tokens from the 4th bin since 57 usec is nearest to the 4th
+ * bin midpoint (31 + (62-31)/2 == 46). Then we remove from the 3rd bin for
+ * the same reason, then from the 5th, etc. */
+ const int bin_removal_order[] = {4, 3, 5, 2, 6, 1, 7, 0, 8, 9};
+
+ /* Remove all tokens from all bins apart from the infinity bin */
+ for (int i = 0; i < BIG_HISTOGRAM_LEN-1 ; i++) {
+ int bin_to_remove = bin_removal_order[i];
+ log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
+ i, bin_to_remove);
+
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
+
+ mi->padding_scheduled_at_usec = current_time - 57;
+ circpad_cell_event_nonpadding_sent(client_side);
+
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
+
+ mi->padding_scheduled_at_usec = current_time - 57;
+ circpad_cell_event_nonpadding_sent(client_side);
+
+ /* Test that we cleaned out this bin. Don't do this in the case of the last
+ bin since the tokens will get refilled */
+ if (i != BIG_HISTOGRAM_LEN - 2) {
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
+ }
+ }
+
+ /* Check that all bins have been refilled */
+ for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
+ tt_int_op(mi->histogram[i], OP_EQ, 2);
+ }
+
+ /* Test below the lowest bin, for coverage */
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 101;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 120;
+ mi->padding_scheduled_at_usec = current_time - 102;
+ mi->histogram[0] = 0;
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_int_op(mi->histogram[1], OP_EQ, 1);
+
+ /* Test above the highest bin, for coverage */
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+ mi->padding_scheduled_at_usec = current_time - 29202;
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1);
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ monotime_disable_test_mocking();
+ tor_free(circ_client_machine.states);
+ testing_disable_reproducible_rng();
+}
+
+/** Test closest token removal strategy with usec */
+static void
+test_circuitpadding_closest_token_removal_usec(void *arg)
+{
+ circpad_machine_runtime_t *mi;
+ (void)arg;
+
+ /* Mock it up */
+ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
+ MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+ testing_enable_reproducible_rng();
+
+ /* Setup test environment (time etc.) */
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ monotime_enable_test_mocking();
+
+ /* Create test machine */
+ helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC);
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(client_side, 0);
+
+ /* move the machine to the right state */
+ circpad_cell_event_nonpadding_received(client_side);
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+
+ /* Get the machine and setup tokens */
+ mi = client_side->padding_info[0];
+ tt_assert(mi);
+
+ /*************************************************************************/
+
+ uint64_t current_time = monotime_absolute_usec();
+
+ /* Test left boundaries of each histogram bin: */
+ const circpad_delay_t bin_left_bounds[] =
+ {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
+ for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
+ tt_uint_op(bin_left_bounds[i], OP_EQ,
+ circpad_histogram_bin_to_usec(mi, i));
+ }
+
+ /* XXX we want to test remove_token_exact and
+ circpad_machine_remove_closest_token() with usec */
+
+ /* Check that all bins have two tokens right now */
+ for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
+ tt_int_op(mi->histogram[i], OP_EQ, 2);
+ }
+
+ /* This is the right order to remove tokens from this histogram. That is, we
+ * first remove tokens from the 4th bin since 57 usec is nearest to the 4th
+ * bin midpoint (31 + (62-31)/2 == 46). Then we remove from the 3rd bin for
+ * the same reason, then from the 5th, etc. */
+ const int bin_removal_order[] = {4, 3, 5, 2, 1, 0, 6, 7, 8, 9};
+
+ /* Remove all tokens from all bins apart from the infinity bin */
+ for (int i = 0; i < BIG_HISTOGRAM_LEN-1 ; i++) {
+ int bin_to_remove = bin_removal_order[i];
+ log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
+ i, bin_to_remove);
+
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
+
+ mi->padding_scheduled_at_usec = current_time - 57;
+ circpad_cell_event_nonpadding_sent(client_side);
+
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
+
+ mi->padding_scheduled_at_usec = current_time - 57;
+ circpad_cell_event_nonpadding_sent(client_side);
+
+ /* Test that we cleaned out this bin. Don't do this in the case of the last
+ bin since the tokens will get refilled */
+ if (i != BIG_HISTOGRAM_LEN - 2) {
+ tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
+ }
+ }
+
+ /* Check that all bins have been refilled */
+ for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
+ tt_int_op(mi->histogram[i], OP_EQ, 2);
+ }
+
+ /* Test below the lowest bin, for coverage */
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 101;
+ circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 120;
+ mi->padding_scheduled_at_usec = current_time - 102;
+ mi->histogram[0] = 0;
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_int_op(mi->histogram[1], OP_EQ, 1);
+
+ /* Test above the highest bin, for coverage */
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+ circ_client_machine.states[CIRCPAD_STATE_BURST].
+ histogram_edges[BIG_HISTOGRAM_LEN-2] = 100;
+ mi->padding_scheduled_at_usec = current_time - 29202;
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1);
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ monotime_disable_test_mocking();
+ tor_free(circ_client_machine.states);
+ testing_disable_reproducible_rng();
+}
+
+/** Test closest token removal strategy with usec */
+static void
+test_circuitpadding_token_removal_exact(void *arg)
+{
+ circpad_machine_runtime_t *mi;
+ (void)arg;
+
+ /* Mock it up */
+ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
+ MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+ testing_enable_reproducible_rng();
+
+ /* Setup test environment (time etc.) */
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ monotime_enable_test_mocking();
+
+ /* Create test machine */
+ helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_EXACT);
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(client_side, 0);
+
+ /* move the machine to the right state */
+ circpad_cell_event_nonpadding_received(client_side);
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+
+ /* Get the machine and setup tokens */
+ mi = client_side->padding_info[0];
+ tt_assert(mi);
+
+ /**********************************************************************/
+ uint64_t current_time = monotime_absolute_usec();
+
+ /* Ensure that we will clear out bin #4 with this usec */
+ mi->padding_scheduled_at_usec = current_time - 57;
+ tt_int_op(mi->histogram[4], OP_EQ, 2);
+ circpad_cell_event_nonpadding_sent(client_side);
+ mi->padding_scheduled_at_usec = current_time - 57;
+ tt_int_op(mi->histogram[4], OP_EQ, 1);
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_int_op(mi->histogram[4], OP_EQ, 0);
+
+ /* Ensure that we will not remove any other tokens even tho we try to, since
+ * this is what the exact strategy dictates */
+ mi->padding_scheduled_at_usec = current_time - 57;
+ circpad_cell_event_nonpadding_sent(client_side);
+ for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
+ if (i != 4) {
+ tt_int_op(mi->histogram[i], OP_EQ, 2);
+ }
+ }
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ monotime_disable_test_mocking();
+ tor_free(circ_client_machine.states);
+ testing_disable_reproducible_rng();
+}
+
+#undef BIG_HISTOGRAM_LEN
+
+void
+test_circuitpadding_tokens(void *arg)
+{
+ const circpad_state_t *state;
+ circpad_machine_runtime_t *mi;
+ int64_t actual_mocked_monotime_start;
+ (void)arg;
+
+ testing_enable_reproducible_rng();
+
+ /** Test plan:
+ *
+ * 1. Test symmetry between bin_to_usec and usec_to_bin
+ * a. Test conversion
+ * b. Test edge transitions (lower, upper)
+ * 2. Test remove higher on an empty bin
+ * a. Normal bin
+ * b. Infinity bin
+ * c. Bin 0
+ * d. No higher
+ * 3. Test remove lower
+ * a. Normal bin
+ * b. Bin 0
+ * c. No lower
+ * 4. Test remove closest
+ * a. Closest lower
+ * b. Closest higher
+ * c. Closest 0
+ * d. Closest Infinity
+ */
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ actual_mocked_monotime_start = MONOTIME_MOCK_START;
+ monotime_set_mock_time_nsec(actual_mocked_monotime_start);
+ monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
+ curr_mocked_time = actual_mocked_monotime_start;
+
+ /* This is needed so that we are not considered to be dormant */
+ note_user_activity(20);
+
+ timers_initialize();
+
+ helper_create_basic_machine();
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side,
+ 0);
+
+ mi = client_side->padding_info[0];
+
+ // Pretend a non-padding cell was sent
+ circpad_cell_event_nonpadding_received(client_side);
+ circpad_cell_event_nonpadding_sent(client_side);
+ /* We have to save the infinity bin because one inf delay
+ * could have been chosen when we transition to burst */
+ circpad_hist_token_t inf_bin = mi->histogram[4];
+
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+
+ state = circpad_machine_current_state(client_side->padding_info[0]);
+
+ // Test 0: convert bin->usec->bin
+ // Bin 0+1 have different semantics
+ for (int bin = 0; bin < 2; bin++) {
+ circpad_delay_t usec =
+ circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
+ int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
+ usec);
+ tt_int_op(bin, OP_EQ, bin2);
+ }
+ for (int bin = 2; bin < state->histogram_len-1; bin++) {
+ circpad_delay_t usec =
+ circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
+ int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
+ usec);
+ tt_int_op(bin, OP_EQ, bin2);
+ /* Verify we round down */
+ bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
+ usec+3);
+ tt_int_op(bin, OP_EQ, bin2);
+
+ bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
+ usec-1);
+ tt_int_op(bin, OP_EQ, bin2+1);
+ }
+
+ // Test 1: converting usec->bin->usec->bin
+ // Bin 0+1 have different semantics.
+ for (circpad_delay_t i = 0; i <= state->histogram_edges[0]; i++) {
+ int bin = circpad_histogram_usec_to_bin(client_side->padding_info[0],
+ i);
+ circpad_delay_t usec =
+ circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
+ int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
+ usec);
+ tt_int_op(bin, OP_EQ, bin2);
+ tt_int_op(i, OP_LE, usec);
+ }
+ for (circpad_delay_t i = state->histogram_edges[0]+1;
+ i <= state->histogram_edges[0] +
+ state->histogram_edges[state->histogram_len-2]; i++) {
+ int bin = circpad_histogram_usec_to_bin(client_side->padding_info[0],
+ i);
+ circpad_delay_t usec =
+ circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
+ int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
+ usec);
+ tt_int_op(bin, OP_EQ, bin2);
+ tt_int_op(i, OP_GE, usec);
+ }
+
+ /* 2.a. Normal higher bin */
+ {
+ tt_int_op(mi->histogram[2], OP_EQ, 2);
+ tt_int_op(mi->histogram[3], OP_EQ, 2);
+ circpad_machine_remove_higher_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1);
+ tt_int_op(mi->histogram[3], OP_EQ, 2);
+ tt_int_op(mi->histogram[2], OP_EQ, 1);
+
+ circpad_machine_remove_higher_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1);
+ tt_int_op(mi->histogram[2], OP_EQ, 0);
+
+ tt_int_op(mi->histogram[3], OP_EQ, 2);
+ circpad_machine_remove_higher_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1);
+ circpad_machine_remove_higher_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1);
+ tt_int_op(mi->histogram[3], OP_EQ, 0);
+ circpad_machine_remove_higher_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1);
+ tt_int_op(mi->histogram[3], OP_EQ, 0);
+ }
+
+ /* 2.b. Higher Infinity bin */
+ {
+ tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
+ circpad_machine_remove_higher_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1);
+ tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
+
+ /* Test past the infinity bin */
+ circpad_machine_remove_higher_token(mi,
+ circpad_histogram_bin_to_usec(mi, 5)+1000000);
+
+ tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
+ }
+
+ /* 2.c. Bin 0 */
+ {
+ tt_int_op(mi->histogram[0], OP_EQ, 0);
+ mi->histogram[0] = 1;
+ circpad_machine_remove_higher_token(mi, state->histogram_edges[0]/2);
+ tt_int_op(mi->histogram[0], OP_EQ, 0);
+ }
+
+ /* Drain the infinity bin and cause a refill */
+ while (inf_bin != 0) {
+ tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
+ circpad_cell_event_nonpadding_received(client_side);
+ inf_bin--;
+ }
+
+ circpad_cell_event_nonpadding_sent(client_side);
+
+ // We should have refilled here.
+ tt_int_op(mi->histogram[4], OP_EQ, 2);
+
+ /* 3.a. Bin 0 */
+ {
+ tt_int_op(mi->histogram[0], OP_EQ, 1);
+ circpad_machine_remove_higher_token(mi, state->histogram_edges[0]/2);
+ tt_int_op(mi->histogram[0], OP_EQ, 0);
+ }
+
+ /* 3.b. Test remove lower normal bin */
+ {
+ tt_int_op(mi->histogram[3], OP_EQ, 2);
+ circpad_machine_remove_lower_token(mi,
+ circpad_histogram_bin_to_usec(mi, 3)+1);
+ circpad_machine_remove_lower_token(mi,
+ circpad_histogram_bin_to_usec(mi, 3)+1);
+ tt_int_op(mi->histogram[3], OP_EQ, 0);
+ tt_int_op(mi->histogram[2], OP_EQ, 2);
+ circpad_machine_remove_lower_token(mi,
+ circpad_histogram_bin_to_usec(mi, 3)+1);
+ circpad_machine_remove_lower_token(mi,
+ circpad_histogram_bin_to_usec(mi, 3)+1);
+ /* 3.c. No lower */
+ circpad_machine_remove_lower_token(mi,
+ circpad_histogram_bin_to_usec(mi, 3)+1);
+ tt_int_op(mi->histogram[2], OP_EQ, 0);
+ }
+
+ /* 4. Test remove closest
+ * a. Closest lower
+ * b. Closest higher
+ * c. Closest 0
+ * d. Closest Infinity
+ */
+ circpad_machine_setup_tokens(mi);
+ tt_int_op(mi->histogram[2], OP_EQ, 2);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1, 0);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1, 0);
+ tt_int_op(mi->histogram[2], OP_EQ, 0);
+ tt_int_op(mi->histogram[3], OP_EQ, 2);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1, 0);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1, 0);
+ tt_int_op(mi->histogram[3], OP_EQ, 0);
+ tt_int_op(mi->histogram[0], OP_EQ, 1);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1, 0);
+ tt_int_op(mi->histogram[0], OP_EQ, 0);
+ tt_int_op(mi->histogram[4], OP_EQ, 2);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 2)+1, 0);
+ tt_int_op(mi->histogram[4], OP_EQ, 2);
+
+ /* 5. Test remove closest usec
+ * a. Closest 0
+ * b. Closest lower (below midpoint)
+ * c. Closest higher (above midpoint)
+ * d. Closest Infinity
+ */
+ circpad_machine_setup_tokens(mi);
+
+ tt_int_op(mi->histogram[0], OP_EQ, 1);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 0)/3, 1);
+ tt_int_op(mi->histogram[0], OP_EQ, 0);
+ tt_int_op(mi->histogram[2], OP_EQ, 2);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 0)/3, 1);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 0)/3, 1);
+ tt_int_op(mi->histogram[2], OP_EQ, 0);
+ tt_int_op(mi->histogram[3], OP_EQ, 2);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 4), 1);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 4), 1);
+ tt_int_op(mi->histogram[3], OP_EQ, 0);
+ tt_int_op(mi->histogram[4], OP_EQ, 2);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 4), 1);
+ circpad_machine_remove_closest_token(mi,
+ circpad_histogram_bin_to_usec(mi, 4), 1);
+ tt_int_op(mi->histogram[4], OP_EQ, 2);
+
+ // XXX: Need more coverage of the actual usec branches
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ monotime_disable_test_mocking();
+ tor_free(circ_client_machine.states);
+ testing_disable_reproducible_rng();
+}
+
+void
+test_circuitpadding_wronghop(void *arg)
+{
+ /**
+ * Test plan:
+ * 1. Padding sent from hop 1 and 3 to client
+ * 2. Send negotiated from hop 1 and 3 to client
+ * 3. Garbled negotiated cell
+ * 4. Padding negotiate sent to client
+ * 5. Send negotiate stop command for unknown machine
+ * 6. Send negotiated to relay
+ * 7. Garbled padding negotiate cell
+ */
+ (void)arg;
+ uint32_t read_bw = 0, overhead_bw = 0;
+ cell_t cell;
+ signed_error_t ret;
+ origin_circuit_t *orig_client;
+ int64_t actual_mocked_monotime_start;
+
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+
+ /* Mock this function so that our cell counting tests don't get confused by
+ * padding that gets sent by scheduled timers. */
+ MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+ testing_enable_reproducible_rng();
+
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ dummy_channel.cmux = circuitmux_alloc();
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
+ &dummy_channel));
+ orig_client = TO_ORIGIN_CIRCUIT(client_side);
+
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ nodes_init();
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ actual_mocked_monotime_start = MONOTIME_MOCK_START;
+ monotime_set_mock_time_nsec(actual_mocked_monotime_start);
+ monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
+ curr_mocked_time = actual_mocked_monotime_start;
+
+ timers_initialize();
+ circpad_machines_init();
+
+ MOCK(node_get_by_id,
+ node_get_by_id_mock);
+
+ MOCK(circuit_package_relay_cell,
+ circuit_package_relay_cell_mock);
+
+ /* Build three hops */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* verify padding was negotiated */
+ tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
+ tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
+
+ /* verify echo was sent */
+ tt_int_op(n_relay_cells, OP_EQ, 1);
+ tt_int_op(n_client_cells, OP_EQ, 1);
+
+ read_bw = orig_client->n_delivered_read_circ_bw;
+ overhead_bw = orig_client->n_overhead_read_circ_bw;
+
+ /* 1. Test padding from first and third hop */
+ circpad_deliver_recognized_relay_cell_events(client_side,
+ RELAY_COMMAND_DROP,
+ TO_ORIGIN_CIRCUIT(client_side)->cpath);
+ tt_int_op(read_bw, OP_EQ,
+ orig_client->n_delivered_read_circ_bw);
+ tt_int_op(overhead_bw, OP_EQ,
+ orig_client->n_overhead_read_circ_bw);
+
+ circpad_deliver_recognized_relay_cell_events(client_side,
+ RELAY_COMMAND_DROP,
+ TO_ORIGIN_CIRCUIT(client_side)->cpath->next->next);
+ tt_int_op(read_bw, OP_EQ,
+ orig_client->n_delivered_read_circ_bw);
+ tt_int_op(overhead_bw, OP_EQ,
+ orig_client->n_overhead_read_circ_bw);
+
+ circpad_deliver_recognized_relay_cell_events(client_side,
+ RELAY_COMMAND_DROP,
+ TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
+ tt_int_op(read_bw, OP_EQ,
+ orig_client->n_delivered_read_circ_bw);
+ tt_int_op(overhead_bw, OP_LT,
+ orig_client->n_overhead_read_circ_bw);
+
+ /* 2. Test padding negotiated not handled from hops 1,3 */
+ ret = circpad_handle_padding_negotiated(client_side, &cell,
+ TO_ORIGIN_CIRCUIT(client_side)->cpath);
+ tt_int_op(ret, OP_EQ, -1);
+
+ ret = circpad_handle_padding_negotiated(client_side, &cell,
+ TO_ORIGIN_CIRCUIT(client_side)->cpath->next->next);
+ tt_int_op(ret, OP_EQ, -1);
+
+ /* 3. Garbled negotiated cell */
+ memset(&cell, 255, sizeof(cell));
+ ret = circpad_handle_padding_negotiated(client_side, &cell,
+ TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
+ tt_int_op(ret, OP_EQ, -1);
+
+ /* 4. Test that negotiate is dropped at origin */
+ read_bw = orig_client->n_delivered_read_circ_bw;
+ overhead_bw = orig_client->n_overhead_read_circ_bw;
+ relay_send_command_from_edge(0, relay_side,
+ RELAY_COMMAND_PADDING_NEGOTIATE,
+ (void*)cell.payload,
+ (size_t)3, NULL);
+ tt_int_op(read_bw, OP_EQ,
+ orig_client->n_delivered_read_circ_bw);
+ tt_int_op(overhead_bw, OP_EQ,
+ orig_client->n_overhead_read_circ_bw);
+
+ tt_int_op(n_relay_cells, OP_EQ, 2);
+ tt_int_op(n_client_cells, OP_EQ, 1);
+
+ /* 5. Test that asking to stop the wrong machine does nothing */
+ circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(client_side),
+ 255, 2, CIRCPAD_COMMAND_STOP, 0);
+ tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
+ tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
+ tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
+ tt_int_op(n_relay_cells, OP_EQ, 3);
+ tt_int_op(n_client_cells, OP_EQ, 2);
+
+ /* 6. Sending negotiated command to relay does nothing */
+ ret = circpad_handle_padding_negotiated(relay_side, &cell, NULL);
+ tt_int_op(ret, OP_EQ, -1);
+
+ /* 7. Test garbled negotiated cell (bad command 255) */
+ memset(&cell, 0, sizeof(cell));
+ ret = circpad_handle_padding_negotiate(relay_side, &cell);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(n_client_cells, OP_EQ, 2);
+
+ /* Test 2: Test no padding */
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
+ &dummy_channel));
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 0);
+
+ /* verify no padding was negotiated */
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+ tt_int_op(n_relay_cells, OP_EQ, 3);
+ tt_int_op(n_client_cells, OP_EQ, 2);
+
+ /* verify no echo was sent */
+ tt_int_op(n_relay_cells, OP_EQ, 3);
+ tt_int_op(n_client_cells, OP_EQ, 2);
+
+ /* Finish circuit */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* Spoof padding negotiated on circuit with no padding */
+ circpad_padding_negotiated(relay_side,
+ CIRCPAD_MACHINE_CIRC_SETUP,
+ CIRCPAD_COMMAND_START,
+ CIRCPAD_RESPONSE_OK, 0);
+
+ /* verify no padding was negotiated */
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+
+ circpad_padding_negotiated(relay_side,
+ CIRCPAD_MACHINE_CIRC_SETUP,
+ CIRCPAD_COMMAND_START,
+ CIRCPAD_RESPONSE_ERR, 0);
+
+ /* verify no padding was negotiated */
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+ circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
+ circuitmux_free(dummy_channel.cmux);
+ monotime_disable_test_mocking();
+ UNMOCK(node_get_by_id);
+ UNMOCK(circuit_package_relay_cell);
+ UNMOCK(circuitmux_attach_circuit);
+ nodes_free();
+ testing_disable_reproducible_rng();
+}
+
+void
+test_circuitpadding_negotiation(void *arg)
+{
+ /**
+ * Test plan:
+ * 1. Test circuit where padding is supported by middle
+ * a. Make sure padding negotiation is sent
+ * b. Test padding negotiation delivery and parsing
+ * 2. Test circuit where padding is unsupported by middle
+ * a. Make sure padding negotiation is not sent
+ * 3. Test failure to negotiate a machine due to desync.
+ */
+ int64_t actual_mocked_monotime_start;
+ (void)arg;
+
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ dummy_channel.cmux = circuitmux_alloc();
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
+
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ nodes_init();
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ actual_mocked_monotime_start = MONOTIME_MOCK_START;
+ monotime_set_mock_time_nsec(actual_mocked_monotime_start);
+ monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
+ curr_mocked_time = actual_mocked_monotime_start;
+
+ timers_initialize();
+ circpad_machines_init();
+
+ MOCK(node_get_by_id,
+ node_get_by_id_mock);
+
+ MOCK(circuit_package_relay_cell,
+ circuit_package_relay_cell_mock);
+
+ /* Build two hops */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* verify padding was negotiated */
+ tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
+ tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
+
+ /* verify echo was sent */
+ tt_int_op(n_relay_cells, OP_EQ, 1);
+ tt_int_op(n_client_cells, OP_EQ, 1);
+
+ /* Finish circuit */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* Test 2: Test no padding */
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 0);
+
+ /* verify no padding was negotiated */
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+ tt_int_op(n_relay_cells, OP_EQ, 1);
+ tt_int_op(n_client_cells, OP_EQ, 1);
+
+ /* verify no echo was sent */
+ tt_int_op(n_relay_cells, OP_EQ, 1);
+ tt_int_op(n_client_cells, OP_EQ, 1);
+
+ /* Finish circuit */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* Force negotiate padding. */
+ circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(client_side),
+ CIRCPAD_MACHINE_CIRC_SETUP,
+ 2, CIRCPAD_COMMAND_START, 0);
+
+ /* verify no padding was negotiated */
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+
+ /* verify no echo was sent */
+ tt_int_op(n_relay_cells, OP_EQ, 1);
+ tt_int_op(n_client_cells, OP_EQ, 1);
+
+ /* 3. Test failure to negotiate a machine due to desync */
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ SMARTLIST_FOREACH(relay_padding_machines,
+ circpad_machine_spec_t *,
+ m, tor_free(m->states); tor_free(m));
+ smartlist_free(relay_padding_machines);
+ relay_padding_machines = smartlist_new();
+
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* verify echo was sent */
+ tt_int_op(n_client_cells, OP_EQ, 2);
+ tt_int_op(n_relay_cells, OP_EQ, 2);
+
+ /* verify no padding was negotiated */
+ tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+ circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
+ circuitmux_free(dummy_channel.cmux);
+ monotime_disable_test_mocking();
+ UNMOCK(node_get_by_id);
+ UNMOCK(circuit_package_relay_cell);
+ UNMOCK(circuitmux_attach_circuit);
+ nodes_free();
+}
+
+static void
+simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay,
+ int padding)
+{
+ char whatevs_key[CPATH_KEY_MATERIAL_LEN];
+ char digest[DIGEST_LEN];
+ tor_addr_t addr;
+
+ // Pretend a non-padding cell was sent
+ circpad_cell_event_nonpadding_sent(client);
+
+ // Receive extend cell at middle
+ circpad_cell_event_nonpadding_received(mid_relay);
+
+ // Advance time a tiny bit so we can calculate an RTT
+ curr_mocked_time += 10 * TOR_NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(curr_mocked_time);
+ monotime_set_mock_time_nsec(curr_mocked_time);
+
+ // Receive extended cell at middle
+ circpad_cell_event_nonpadding_sent(mid_relay);
+
+ // Receive extended cell at first hop
+ circpad_cell_event_nonpadding_received(client);
+
+ // Add a hop to cpath
+ crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t));
+ cpath_extend_linked_list(&TO_ORIGIN_CIRCUIT(client)->cpath, hop);
+
+ hop->magic = CRYPT_PATH_MAGIC;
+ hop->state = CPATH_STATE_OPEN;
+
+ // add an extend info to indicate if this node supports padding or not.
+ // (set the first byte of the digest for our mocked node_get_by_id)
+ digest[0] = padding;
+
+ hop->extend_info = extend_info_new(
+ padding ? "padding" : "non-padding",
+ digest, NULL, NULL, NULL,
+ &addr, padding);
+
+ cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0);
+
+ hop->package_window = circuit_initial_package_window();
+ hop->deliver_window = CIRCWINDOW_START;
+
+ // Signal that the hop was added
+ circpad_machine_event_circ_added_hop(TO_ORIGIN_CIRCUIT(client));
+}
+
+static circpad_machine_spec_t *
+helper_create_length_machine(void)
+{
+ circpad_machine_spec_t *ret =
+ tor_malloc_zero(sizeof(circpad_machine_spec_t));
+
+ /* Start, burst */
+ circpad_machine_states_init(ret, 2);
+
+ ret->states[CIRCPAD_STATE_START].
+ next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
+
+ ret->states[CIRCPAD_STATE_BURST].
+ next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
+
+ ret->states[CIRCPAD_STATE_BURST].
+ next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END;
+
+ ret->states[CIRCPAD_STATE_BURST].
+ next_state[CIRCPAD_EVENT_BINS_EMPTY] = CIRCPAD_STATE_END;
+
+ /* No token removal.. end via state_length only */
+ ret->states[CIRCPAD_STATE_BURST].token_removal =
+ CIRCPAD_TOKEN_REMOVAL_NONE;
+
+ /* Let's have this one end after 12 packets */
+ ret->states[CIRCPAD_STATE_BURST].length_dist.type = CIRCPAD_DIST_UNIFORM;
+ ret->states[CIRCPAD_STATE_BURST].length_dist.param1 = 12;
+ ret->states[CIRCPAD_STATE_BURST].length_dist.param2 = 13;
+ ret->states[CIRCPAD_STATE_BURST].max_length = 12;
+
+ ret->states[CIRCPAD_STATE_BURST].histogram_len = 4;
+
+ ret->states[CIRCPAD_STATE_BURST].histogram_edges[0] = 0;
+ ret->states[CIRCPAD_STATE_BURST].histogram_edges[1] = 1;
+ ret->states[CIRCPAD_STATE_BURST].histogram_edges[2] = 1000000;
+ ret->states[CIRCPAD_STATE_BURST].histogram_edges[3] = 10000000;
+
+ ret->states[CIRCPAD_STATE_BURST].histogram[0] = 0;
+ ret->states[CIRCPAD_STATE_BURST].histogram[1] = 0;
+ ret->states[CIRCPAD_STATE_BURST].histogram[2] = 6;
+
+ ret->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 6;
+ ret->states[CIRCPAD_STATE_BURST].use_rtt_estimate = 0;
+ ret->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 0;
+
+ return ret;
+}
+
+static circpad_machine_spec_t *
+helper_create_conditional_machine(void)
+{
+ circpad_machine_spec_t *ret =
+ tor_malloc_zero(sizeof(circpad_machine_spec_t));
+
+ /* Start, burst */
+ circpad_machine_states_init(ret, 2);
+
+ ret->states[CIRCPAD_STATE_START].
+ next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
+
+ ret->states[CIRCPAD_STATE_BURST].
+ next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
+
+ ret->states[CIRCPAD_STATE_BURST].
+ next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END;
+
+ /* Use EXACT removal strategy, otherwise setup_tokens() does not work */
+ ret->states[CIRCPAD_STATE_BURST].token_removal =
+ CIRCPAD_TOKEN_REMOVAL_EXACT;
+
+ ret->states[CIRCPAD_STATE_BURST].histogram_len = 3;
+
+ ret->states[CIRCPAD_STATE_BURST].histogram_edges[0] = 0;
+ ret->states[CIRCPAD_STATE_BURST].histogram_edges[1] = 1;
+ ret->states[CIRCPAD_STATE_BURST].histogram_edges[2] = 1000000;
+
+ ret->states[CIRCPAD_STATE_BURST].histogram[0] = 6;
+ ret->states[CIRCPAD_STATE_BURST].histogram[1] = 0;
+ ret->states[CIRCPAD_STATE_BURST].histogram[2] = 0;
+
+ ret->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 6;
+ ret->states[CIRCPAD_STATE_BURST].use_rtt_estimate = 0;
+ ret->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 1;
+
+ return ret;
+}
+
+static void
+helper_create_conditional_machines(void)
+{
+ circpad_machine_spec_t *add = helper_create_conditional_machine();
+
+ if (!origin_padding_machines)
+ origin_padding_machines = smartlist_new();
+ if (!relay_padding_machines)
+ relay_padding_machines = smartlist_new();
+
+ add->machine_num = 2;
+ add->is_origin_side = 1;
+ add->should_negotiate_end = 1;
+ add->target_hopnum = 2;
+
+ /* Let's have this one end after 4 packets */
+ add->states[CIRCPAD_STATE_BURST].length_dist.type = CIRCPAD_DIST_UNIFORM;
+ add->states[CIRCPAD_STATE_BURST].length_dist.param1 = 4;
+ add->states[CIRCPAD_STATE_BURST].length_dist.param2 = 4;
+ add->states[CIRCPAD_STATE_BURST].max_length = 4;
+
+ add->conditions.requires_vanguards = 0;
+ add->conditions.min_hops = 2;
+ add->conditions.apply_state_mask = CIRCPAD_CIRC_BUILDING|
+ CIRCPAD_CIRC_NO_STREAMS|CIRCPAD_CIRC_HAS_RELAY_EARLY;
+ add->conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
+ circpad_register_padding_machine(add, origin_padding_machines);
+
+ add = helper_create_conditional_machine();
+ add->machine_num = 3;
+ add->is_origin_side = 1;
+ add->should_negotiate_end = 1;
+ add->target_hopnum = 2;
+
+ /* Let's have this one end after 4 packets */
+ add->states[CIRCPAD_STATE_BURST].length_dist.type = CIRCPAD_DIST_UNIFORM;
+ add->states[CIRCPAD_STATE_BURST].length_dist.param1 = 4;
+ add->states[CIRCPAD_STATE_BURST].length_dist.param2 = 4;
+ add->states[CIRCPAD_STATE_BURST].max_length = 4;
+
+ add->conditions.requires_vanguards = 1;
+ add->conditions.min_hops = 3;
+ add->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED|
+ CIRCPAD_CIRC_STREAMS|CIRCPAD_CIRC_HAS_NO_RELAY_EARLY;
+ add->conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
+ circpad_register_padding_machine(add, origin_padding_machines);
+
+ add = helper_create_conditional_machine();
+ add->machine_num = 2;
+ circpad_register_padding_machine(add, relay_padding_machines);
+
+ add = helper_create_conditional_machine();
+ add->machine_num = 3;
+ circpad_register_padding_machine(add, relay_padding_machines);
+}
+
+void
+test_circuitpadding_state_length(void *arg)
+{
+ /**
+ * Test plan:
+ * * Explicitly test that with no token removal enabled, we hit
+ * the state length limit due to either padding, or non-padding.
+ * * Repeat test with an arbitrary token removal strategy, and
+ * verify that if we run out of tokens due to padding before we
+ * hit the state length, we still go to state end (all our
+ * token removal tests only test nonpadding token removal).
+ */
+ int64_t actual_mocked_monotime_start;
+ (void)arg;
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+ MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
+
+ nodes_init();
+ dummy_channel.cmux = circuitmux_alloc();
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
+ &dummy_channel));
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ actual_mocked_monotime_start = MONOTIME_MOCK_START;
+ monotime_set_mock_time_nsec(actual_mocked_monotime_start);
+ monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
+ curr_mocked_time = actual_mocked_monotime_start;
+
+ /* This is needed so that we are not considered to be dormant */
+ note_user_activity(20);
+
+ timers_initialize();
+ circpad_machine_spec_t *client_machine =
+ helper_create_length_machine();
+
+ MOCK(circuit_package_relay_cell,
+ circuit_package_relay_cell_mock);
+ MOCK(node_get_by_id,
+ node_get_by_id_mock);
+
+ client_side->padding_machine[0] = client_machine;
+ client_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(client_side, 0);
+ circpad_machine_runtime_t *mi = client_side->padding_info[0];
+
+ circpad_cell_event_padding_sent(client_side);
+ tt_i64_op(mi->state_length, OP_EQ, 12);
+ tt_ptr_op(mi->histogram, OP_EQ, NULL);
+
+ /* Verify that non-padding does not change our state length */
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_i64_op(mi->state_length, OP_EQ, 12);
+
+ /* verify that sending padding changes our state length */
+ for (uint64_t i = mi->state_length-1; i > 0; i--) {
+ circpad_send_padding_cell_for_callback(mi);
+ tt_i64_op(mi->state_length, OP_EQ, i);
+ }
+ circpad_send_padding_cell_for_callback(mi);
+
+ tt_i64_op(mi->state_length, OP_EQ, -1);
+ tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
+
+ /* Restart machine */
+ mi->current_state = CIRCPAD_STATE_START;
+
+ /* Now, count nonpadding as part of the state length */
+ client_machine->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 1;
+
+ circpad_cell_event_padding_sent(client_side);
+ tt_i64_op(mi->state_length, OP_EQ, 12);
+
+ /* Verify that non-padding does change our state length now */
+ for (uint64_t i = mi->state_length-1; i > 0; i--) {
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_i64_op(mi->state_length, OP_EQ, i);
+ }
+
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_i64_op(mi->state_length, OP_EQ, -1);
+ tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
+
+ /* Now, just test token removal when we send padding */
+ client_machine->states[CIRCPAD_STATE_BURST].token_removal =
+ CIRCPAD_TOKEN_REMOVAL_EXACT;
+
+ /* Restart machine */
+ mi->current_state = CIRCPAD_STATE_START;
+ circpad_cell_event_padding_sent(client_side);
+ tt_i64_op(mi->state_length, OP_EQ, 12);
+ tt_ptr_op(mi->histogram, OP_NE, NULL);
+ tt_int_op(mi->chosen_bin, OP_EQ, 2);
+
+ /* verify that sending padding changes our state length and
+ * our histogram now */
+ for (uint32_t i = mi->histogram[2]-1; i > 0; i--) {
+ circpad_send_padding_cell_for_callback(mi);
+ tt_int_op(mi->chosen_bin, OP_EQ, 2);
+ tt_int_op(mi->histogram[2], OP_EQ, i);
+ }
+
+ tt_i64_op(mi->state_length, OP_EQ, 7);
+ tt_int_op(mi->histogram[2], OP_EQ, 1);
+
+ circpad_send_padding_cell_for_callback(mi);
+ tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
+
+ done:
+ tor_free(client_machine->states);
+ tor_free(client_machine);
+
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+
+ circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
+ circuitmux_free(dummy_channel.cmux);
+ timers_shutdown();
+ monotime_disable_test_mocking();
+ UNMOCK(circuit_package_relay_cell);
+ UNMOCK(circuitmux_attach_circuit);
+ UNMOCK(node_get_by_id);
+
+ return;
+}
+
+void
+test_circuitpadding_conditions(void *arg)
+{
+ /**
+ * Test plan:
+ * 0. Make a few origin and client machines with diff conditions
+ * * vanguards, purposes, has_opened circs, no relay early
+ * * Client side should_negotiate_end
+ * * Length limits
+ * 1. Test STATE_END transitions
+ * 2. Test new machine after end with same conditions
+ * 3. Test new machine due to changed conditions
+ * * Esp: built event, no relay early, no streams
+ * XXX: Diff test:
+ * 1. Test STATE_END with pending timers
+ * 2. Test marking a circuit before padding callback fires
+ * 3. Test freeing a circuit before padding callback fires
+ */
+ int64_t actual_mocked_monotime_start;
+ (void)arg;
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+ testing_enable_reproducible_rng();
+
+ nodes_init();
+ dummy_channel.cmux = circuitmux_alloc();
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
+ &dummy_channel));
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ actual_mocked_monotime_start = MONOTIME_MOCK_START;
+ monotime_set_mock_time_nsec(actual_mocked_monotime_start);
+ monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
+ curr_mocked_time = actual_mocked_monotime_start;
+
+ /* This is needed so that we are not considered to be dormant */
+ note_user_activity(20);
+
+ timers_initialize();
+ helper_create_conditional_machines();
+
+ MOCK(circuit_package_relay_cell,
+ circuit_package_relay_cell_mock);
+ MOCK(node_get_by_id,
+ node_get_by_id_mock);
+
+ /* Simulate extend. This should result in the original machine getting
+ * added, since the circuit is not built */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* Verify that machine #2 is added */
+ tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
+ tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
+
+ /* Deliver a padding cell to the client, to trigger burst state */
+ circpad_cell_event_padding_sent(client_side);
+
+ /* This should have trigger length shutdown condition on client.. */
+ tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+
+ /* Verify machine is gone from both sides */
+ tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+
+ /* Send another event.. verify machine gets re-added properly
+ * (test race with shutdown) */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
+ tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
+
+ TO_ORIGIN_CIRCUIT(client_side)->p_streams = 0;
+ circpad_machine_event_circ_has_no_streams(TO_ORIGIN_CIRCUIT(client_side));
+ tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
+ tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
+
+ /* Now make the circuit opened and send built event */
+ TO_ORIGIN_CIRCUIT(client_side)->has_opened = 1;
+ circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side));
+ tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
+ tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
+
+ TO_ORIGIN_CIRCUIT(client_side)->remaining_relay_early_cells = 0;
+ circpad_machine_event_circ_has_no_relay_early(
+ TO_ORIGIN_CIRCUIT(client_side));
+ tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
+ tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
+
+ get_options_mutable()->HSLayer2Nodes = (void*)1;
+ TO_ORIGIN_CIRCUIT(client_side)->p_streams = (void*)1;
+ circpad_machine_event_circ_has_streams(TO_ORIGIN_CIRCUIT(client_side));
+
+ /* Verify different machine is added */
+ tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 3);
+ tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 3);
+
+ /* Hold off on negotiated */
+ deliver_negotiated = 0;
+
+ /* Deliver a padding cell to the client, to trigger burst state */
+ circpad_cell_event_padding_sent(client_side);
+
+ /* This should have trigger length shutdown condition on client
+ * but not the response for the padding machine */
+ tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
+
+ /* Verify machine is gone from the relay (but negotiated not back yet */
+ tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+
+ /* Add another hop and verify it's back */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 3);
+ tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 3);
+
+ tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
+ tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
+
+ done:
+ /* XXX: Free everything */
+ testing_disable_reproducible_rng();
+ return;
+}
+
+/** Disabled unstable test until #29298 is implemented (see #29122) */
+#if 0
+void
+test_circuitpadding_circuitsetup_machine(void *arg)
+{
+ int64_t actual_mocked_monotime_start;
+ /**
+ * Test case plan:
+ *
+ * 1. Simulate a normal circuit setup pattern
+ * a. Application traffic
+ *
+ * FIXME: This should focus more on exercising the machine
+ * features rather than actual traffic patterns. For example,
+ * test cancellation and bins empty/refill
+ */
+ (void)arg;
+
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+
+ dummy_channel.cmux = circuitmux_alloc();
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
+
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ nodes_init();
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ actual_mocked_monotime_start = MONOTIME_MOCK_START;
+ monotime_set_mock_time_nsec(actual_mocked_monotime_start);
+ monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
+ curr_mocked_time = actual_mocked_monotime_start;
+
+ timers_initialize();
+ circpad_machines_init();
+
+ MOCK(circuit_package_relay_cell,
+ circuit_package_relay_cell_mock);
+ MOCK(node_get_by_id,
+ node_get_by_id_mock);
+
+ /* Test case #1: Build a 3 hop circuit, then wait and let pad */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ tt_int_op(n_client_cells, OP_EQ, 1);
+ tt_int_op(n_relay_cells, OP_EQ, 1);
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+ tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ tt_int_op(relay_side->padding_info[0]->is_padding_timer_scheduled,
+ OP_EQ, 0);
+ timers_advance_and_run(2000);
+ tt_int_op(n_client_cells, OP_EQ, 2);
+ tt_int_op(n_relay_cells, OP_EQ, 1);
+
+ tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_GAP);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ timers_advance_and_run(5000);
+ tt_int_op(n_client_cells, OP_EQ, 2);
+ tt_int_op(n_relay_cells, OP_EQ, 2);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ timers_advance_and_run(2000);
+ tt_int_op(n_client_cells, OP_EQ, 3);
+ tt_int_op(n_relay_cells, OP_EQ, 2);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ timers_advance_and_run(5000);
+ tt_int_op(n_client_cells, OP_EQ, 3);
+ tt_int_op(n_relay_cells, OP_EQ, 3);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ timers_advance_and_run(2000);
+ tt_int_op(n_client_cells, OP_EQ, 4);
+ tt_int_op(n_relay_cells, OP_EQ, 3);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ timers_advance_and_run(5000);
+ tt_int_op(n_client_cells, OP_EQ, 4);
+ tt_int_op(n_relay_cells, OP_EQ, 4);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ timers_advance_and_run(2000);
+ tt_int_op(n_client_cells, OP_EQ, 5);
+ tt_int_op(n_relay_cells, OP_EQ, 4);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ timers_advance_and_run(5000);
+ tt_int_op(n_client_cells, OP_EQ, 5);
+ tt_int_op(n_relay_cells, OP_EQ, 5);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ timers_advance_and_run(2000);
+ tt_int_op(n_client_cells, OP_EQ, 6);
+ tt_int_op(n_relay_cells, OP_EQ, 5);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ timers_advance_and_run(5000);
+ tt_int_op(n_client_cells, OP_EQ, 6);
+ tt_int_op(n_relay_cells, OP_EQ, 6);
+
+ tt_int_op(client_side->padding_info[0]->current_state,
+ OP_EQ, CIRCPAD_STATE_END);
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ tt_int_op(relay_side->padding_info[0]->current_state,
+ OP_EQ, CIRCPAD_STATE_GAP);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+
+ /* Verify we can't schedule padding in END state */
+ circpad_decision_t ret =
+ circpad_machine_schedule_padding(client_side->padding_info[0]);
+ tt_int_op(ret, OP_EQ, CIRCPAD_STATE_UNCHANGED);
+
+ /* Simulate application traffic */
+ circpad_cell_event_nonpadding_sent(client_side);
+ circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_OUT);
+ circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_IN);
+ circpad_deliver_recognized_relay_cell_events(client_side, RELAY_COMMAND_DATA,
+ TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
+
+ tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+
+ tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+ tt_int_op(n_client_cells, OP_EQ, 6);
+ tt_int_op(n_relay_cells, OP_EQ, 7);
+
+ // Test timer cancellation
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ timers_advance_and_run(5000);
+ circpad_cell_event_padding_received(client_side);
+
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+ tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_GAP);
+
+ tt_int_op(n_client_cells, OP_EQ, 8);
+ tt_int_op(n_relay_cells, OP_EQ, 8);
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+
+ /* Test timer cancel due to state rules */
+ circpad_cell_event_nonpadding_sent(client_side);
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_EQ, 0);
+ circpad_cell_event_padding_received(client_side);
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+
+ /* Simulate application traffic to cancel timer */
+ circpad_cell_event_nonpadding_sent(client_side);
+ circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_OUT);
+ circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_IN);
+ circpad_deliver_recognized_relay_cell_events(client_side, RELAY_COMMAND_DATA,
+ TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
+
+ tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+
+ tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+
+ /* No cells sent, except negotiate end from relay */
+ tt_int_op(n_client_cells, OP_EQ, 8);
+ tt_int_op(n_relay_cells, OP_EQ, 9);
+
+ /* Test mark for close and free */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ timers_advance_and_run(5000);
+ circpad_cell_event_padding_received(client_side);
+
+ tt_int_op(n_client_cells, OP_EQ, 10);
+ tt_int_op(n_relay_cells, OP_EQ, 10);
+
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_BURST);
+ tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_GAP);
+
+ tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
+ OP_NE, 0);
+ circuit_mark_for_close(client_side, END_CIRC_REASON_FLAG_REMOTE);
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+ timers_advance_and_run(5000);
+
+ /* No cells sent */
+ tt_int_op(n_client_cells, OP_EQ, 10);
+ tt_int_op(n_relay_cells, OP_EQ, 10);
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+
+ circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
+ circuitmux_free(dummy_channel.cmux);
+ timers_shutdown();
+ monotime_disable_test_mocking();
+ UNMOCK(circuit_package_relay_cell);
+ UNMOCK(circuitmux_attach_circuit);
+
+ return;
+}
+#endif /* 0 */
+
+/** Helper function: Initializes a padding machine where every state uses the
+ * uniform probability distribution. */
+static void
+helper_circpad_circ_distribution_machine_setup(int min, int max)
+{
+ circpad_machine_states_init(&circ_client_machine, 7);
+
+ circpad_state_t *zero_st = &circ_client_machine.states[0];
+ zero_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 1;
+ zero_st->iat_dist.type = CIRCPAD_DIST_UNIFORM;
+ /* param2 is upper bound, param1 is lower */
+ zero_st->iat_dist.param1 = min;
+ zero_st->iat_dist.param2 = max;
+ zero_st->dist_added_shift_usec = min;
+ zero_st->dist_max_sample_usec = max;
+
+ circpad_state_t *first_st = &circ_client_machine.states[1];
+ first_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 2;
+ first_st->iat_dist.type = CIRCPAD_DIST_LOGISTIC;
+ /* param1 is Mu, param2 is sigma. */
+ first_st->iat_dist.param1 = 9;
+ first_st->iat_dist.param2 = 3;
+ first_st->dist_added_shift_usec = min;
+ first_st->dist_max_sample_usec = max;
+
+ circpad_state_t *second_st = &circ_client_machine.states[2];
+ second_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 3;
+ second_st->iat_dist.type = CIRCPAD_DIST_LOG_LOGISTIC;
+ /* param1 is Alpha, param2 is 1.0/Beta */
+ second_st->iat_dist.param1 = 1;
+ second_st->iat_dist.param2 = 0.5;
+ second_st->dist_added_shift_usec = min;
+ second_st->dist_max_sample_usec = max;
+
+ circpad_state_t *third_st = &circ_client_machine.states[3];
+ third_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 4;
+ third_st->iat_dist.type = CIRCPAD_DIST_GEOMETRIC;
+ /* param1 is 'p' (success probability) */
+ third_st->iat_dist.param1 = 0.2;
+ third_st->dist_added_shift_usec = min;
+ third_st->dist_max_sample_usec = max;
+
+ circpad_state_t *fourth_st = &circ_client_machine.states[4];
+ fourth_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 5;
+ fourth_st->iat_dist.type = CIRCPAD_DIST_WEIBULL;
+ /* param1 is k, param2 is Lambda */
+ fourth_st->iat_dist.param1 = 1.5;
+ fourth_st->iat_dist.param2 = 1;
+ fourth_st->dist_added_shift_usec = min;
+ fourth_st->dist_max_sample_usec = max;
+
+ circpad_state_t *fifth_st = &circ_client_machine.states[5];
+ fifth_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 6;
+ fifth_st->iat_dist.type = CIRCPAD_DIST_PARETO;
+ /* param1 is sigma, param2 is xi */
+ fifth_st->iat_dist.param1 = 1;
+ fifth_st->iat_dist.param2 = 5;
+ fifth_st->dist_added_shift_usec = min;
+ fifth_st->dist_max_sample_usec = max;
+}
+
+/** Simple test that the padding delays sampled from a uniform distribution
+ * actually fail within the uniform distribution range. */
+static void
+test_circuitpadding_sample_distribution(void *arg)
+{
+ circpad_machine_runtime_t *mi;
+ int n_samples;
+ int n_states;
+
+ (void) arg;
+
+ /* mock this function so that we dont actually schedule any padding */
+ MOCK(circpad_machine_schedule_padding,
+ circpad_machine_schedule_padding_mock);
+ testing_enable_reproducible_rng();
+
+ /* Initialize a machine with multiple probability distributions */
+ circpad_machines_init();
+ helper_circpad_circ_distribution_machine_setup(0, 10);
+
+ /* Initialize machine and circuits */
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(client_side, 0);
+ mi = client_side->padding_info[0];
+
+ /* For every state, sample a bunch of values from the distribution and ensure
+ * they fall within range. */
+ for (n_states = 0 ; n_states < 6; n_states++) {
+ /* Make sure we in the right state */
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, n_states);
+
+ for (n_samples = 0; n_samples < 100; n_samples++) {
+ circpad_delay_t delay = circpad_machine_sample_delay(mi);
+ tt_int_op(delay, OP_GE, 0);
+ tt_int_op(delay, OP_LE, 10);
+ }
+
+ /* send a non-padding cell to move to the next machine state */
+ circpad_cell_event_nonpadding_received(client_side);
+ }
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ UNMOCK(circpad_machine_schedule_padding);
+ testing_disable_reproducible_rng();
+}
+
+static circpad_decision_t
+circpad_machine_spec_transition_mock(circpad_machine_runtime_t *mi,
+ circpad_event_t event)
+{
+ (void) mi;
+ (void) event;
+
+ return CIRCPAD_STATE_UNCHANGED;
+}
+
+/* Test per-machine padding rate limits */
+static void
+test_circuitpadding_machine_rate_limiting(void *arg)
+{
+ (void) arg;
+ bool retval;
+ circpad_machine_runtime_t *mi;
+ int i;
+
+ /* Ignore machine transitions for the purposes of this function, we only
+ * really care about padding counts */
+ MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock);
+ MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
+ testing_enable_reproducible_rng();
+
+ /* Setup machine and circuits */
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ helper_create_basic_machine();
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(client_side, 0);
+ mi = client_side->padding_info[0];
+ /* Set up the machine info so that we can get through the basic functions */
+ mi->state_length = CIRCPAD_STATE_LENGTH_INFINITE;
+
+ /* First we are going to test the per-machine rate limits */
+ circ_client_machine.max_padding_percent = 50;
+ circ_client_machine.allowed_padding_count = 100;
+
+ /* Check padding limit, should be fine since we haven't sent anything yet. */
+ retval = circpad_machine_reached_padding_limit(mi);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Send 99 padding cells which is below circpad_global_allowed_cells=100, so
+ * the rate limit will not trigger */
+ for (i=0;i<99;i++) {
+ circpad_send_padding_cell_for_callback(mi);
+ }
+ retval = circpad_machine_reached_padding_limit(mi);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Now send another padding cell to pass circpad_global_allowed_cells=100,
+ and see that the limit will trigger */
+ circpad_send_padding_cell_for_callback(mi);
+ retval = circpad_machine_reached_padding_limit(mi);
+ tt_int_op(retval, OP_EQ, 1);
+
+ retval = circpad_machine_schedule_padding(mi);
+ tt_int_op(retval, OP_EQ, CIRCPAD_STATE_UNCHANGED);
+
+ /* Cover wrap */
+ for (;i<UINT16_MAX;i++) {
+ circpad_send_padding_cell_for_callback(mi);
+ }
+ tt_int_op(mi->padding_sent, OP_EQ, UINT16_MAX/2+1);
+
+ tt_ptr_op(client_side->padding_info[0], OP_EQ, mi);
+ for (i=0;i<UINT16_MAX;i++) {
+ circpad_cell_event_nonpadding_sent(client_side);
+ }
+
+ tt_int_op(mi->nonpadding_sent, OP_EQ, UINT16_MAX/2);
+ tt_int_op(mi->padding_sent, OP_EQ, UINT16_MAX/4+1);
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ testing_disable_reproducible_rng();
+}
+
+/* Test global padding rate limits */
+static void
+test_circuitpadding_global_rate_limiting(void *arg)
+{
+ (void) arg;
+ bool retval;
+ circpad_machine_runtime_t *mi;
+ int i;
+ int64_t actual_mocked_monotime_start;
+
+ /* Ignore machine transitions for the purposes of this function, we only
+ * really care about padding counts */
+ MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock);
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+ MOCK(circuit_package_relay_cell,
+ circuit_package_relay_cell_mock);
+ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
+ testing_enable_reproducible_rng();
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ actual_mocked_monotime_start = MONOTIME_MOCK_START;
+ monotime_set_mock_time_nsec(actual_mocked_monotime_start);
+ monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
+ curr_mocked_time = actual_mocked_monotime_start;
+ timers_initialize();
+
+ client_side = TO_CIRCUIT(origin_circuit_new());
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ dummy_channel.cmux = circuitmux_alloc();
+
+ /* Setup machine and circuits */
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ helper_create_basic_machine();
+ relay_side->padding_machine[0] = &circ_client_machine;
+ relay_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(relay_side, 0);
+ mi = relay_side->padding_info[0];
+ /* Set up the machine info so that we can get through the basic functions */
+ mi->state_length = CIRCPAD_STATE_LENGTH_INFINITE;
+
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* Now test the global limits by setting up the consensus */
+ networkstatus_t vote1;
+ vote1.net_params = smartlist_new();
+ smartlist_split_string(vote1.net_params,
+ "circpad_global_allowed_cells=100 circpad_global_max_padding_pct=50",
+ NULL, 0, 0);
+ /* Register global limits with the padding subsystem */
+ circpad_new_consensus_params(&vote1);
+
+ /* Check padding limit, should be fine since we haven't sent anything yet. */
+ retval = circpad_machine_reached_padding_limit(mi);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Send 99 padding cells which is below circpad_global_allowed_cells=100, so
+ * the rate limit will not trigger */
+ for (i=0;i<99;i++) {
+ circpad_send_padding_cell_for_callback(mi);
+ }
+ retval = circpad_machine_reached_padding_limit(mi);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Now send another padding cell to pass circpad_global_allowed_cells=100,
+ and see that the limit will trigger */
+ circpad_send_padding_cell_for_callback(mi);
+ retval = circpad_machine_reached_padding_limit(mi);
+ tt_int_op(retval, OP_EQ, 1);
+
+ retval = circpad_machine_schedule_padding(mi);
+ tt_int_op(retval, OP_EQ, CIRCPAD_STATE_UNCHANGED);
+
+ /* Now send 92 non-padding cells to get near the
+ * circpad_global_max_padding_pct=50 limit; in particular with 96 non-padding
+ * cells, the padding traffic is still 51% of total traffic so limit should
+ * trigger */
+ for (i=0;i<92;i++) {
+ circpad_cell_event_nonpadding_sent(relay_side);
+ }
+ retval = circpad_machine_reached_padding_limit(mi);
+ tt_int_op(retval, OP_EQ, 1);
+
+ /* Send another non-padding cell to bring the padding traffic to 50% of total
+ * traffic and get past the limit */
+ circpad_cell_event_nonpadding_sent(relay_side);
+ retval = circpad_machine_reached_padding_limit(mi);
+ tt_int_op(retval, OP_EQ, 0);
+
+ done:
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+ circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
+ circuitmux_free(dummy_channel.cmux);
+ SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
+ smartlist_free(vote1.net_params);
+ testing_disable_reproducible_rng();
+}
+
+/* Test reduced and disabled padding */
+static void
+test_circuitpadding_reduce_disable(void *arg)
+{
+ (void) arg;
+ int64_t actual_mocked_monotime_start;
+
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+ testing_enable_reproducible_rng();
+
+ nodes_init();
+ dummy_channel.cmux = circuitmux_alloc();
+ relay_side = (circuit_t *)new_fake_orcirc(&dummy_channel,
+ &dummy_channel);
+ client_side = (circuit_t *)origin_circuit_new();
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ circpad_machines_init();
+ helper_create_conditional_machines();
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ actual_mocked_monotime_start = MONOTIME_MOCK_START;
+ monotime_set_mock_time_nsec(actual_mocked_monotime_start);
+ monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
+ curr_mocked_time = actual_mocked_monotime_start;
+ timers_initialize();
+
+ /* This is needed so that we are not considered to be dormant */
+ note_user_activity(20);
+
+ MOCK(circuit_package_relay_cell,
+ circuit_package_relay_cell_mock);
+ MOCK(node_get_by_id,
+ node_get_by_id_mock);
+
+ /* Simulate extend. This should result in the original machine getting
+ * added, since the circuit is not built */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* Verify that machine #2 is added */
+ tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
+ tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
+
+ /* Deliver a padding cell to the client, to trigger burst state */
+ circpad_cell_event_padding_sent(client_side);
+
+ /* This should have trigger length shutdown condition on client.. */
+ tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+
+ /* Verify machine is gone from both sides */
+ tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+
+ /* Now test the reduced padding machine by setting up the consensus */
+ networkstatus_t vote1;
+ vote1.net_params = smartlist_new();
+ smartlist_split_string(vote1.net_params,
+ "circpad_padding_reduced=1", NULL, 0, 0);
+
+ /* Register reduced padding machine with the padding subsystem */
+ circpad_new_consensus_params(&vote1);
+
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* Verify that machine #0 is added */
+ tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
+ tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
+
+ tt_int_op(
+ circpad_machine_reached_padding_limit(client_side->padding_info[0]),
+ OP_EQ, 0);
+ tt_int_op(
+ circpad_machine_reached_padding_limit(relay_side->padding_info[0]),
+ OP_EQ, 0);
+
+ /* Test that machines get torn down when padding is disabled */
+ SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
+ smartlist_free(vote1.net_params);
+ vote1.net_params = smartlist_new();
+ smartlist_split_string(vote1.net_params,
+ "circpad_padding_disabled=1", NULL, 0, 0);
+
+ /* Register reduced padding machine with the padding subsystem */
+ circpad_new_consensus_params(&vote1);
+
+ tt_int_op(
+ circpad_machine_schedule_padding(client_side->padding_info[0]),
+ OP_EQ, CIRCPAD_STATE_UNCHANGED);
+ tt_int_op(
+ circpad_machine_schedule_padding(relay_side->padding_info[0]),
+ OP_EQ, CIRCPAD_STATE_UNCHANGED);
+
+ /* Signal that circuit is built: this event causes us to re-evaluate
+ * machine conditions (which don't apply because padding is disabled). */
+ circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side));
+
+ tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+
+ SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
+ smartlist_free(vote1.net_params);
+ vote1.net_params = NULL;
+ circpad_new_consensus_params(&vote1);
+
+ get_options_mutable()->ReducedCircuitPadding = 1;
+
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* Verify that machine #0 is added */
+ tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
+ tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
+
+ tt_int_op(
+ circpad_machine_reached_padding_limit(client_side->padding_info[0]),
+ OP_EQ, 0);
+ tt_int_op(
+ circpad_machine_reached_padding_limit(relay_side->padding_info[0]),
+ OP_EQ, 0);
+
+ get_options_mutable()->CircuitPadding = 0;
+
+ tt_int_op(
+ circpad_machine_schedule_padding(client_side->padding_info[0]),
+ OP_EQ, CIRCPAD_STATE_UNCHANGED);
+ tt_int_op(
+ circpad_machine_schedule_padding(relay_side->padding_info[0]),
+ OP_EQ, CIRCPAD_STATE_UNCHANGED);
+
+ /* Signal that circuit is built: this event causes us to re-evaluate
+ * machine conditions (which don't apply because padding is disabled). */
+
+ circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side));
+
+ tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
+
+ done:
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+ circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
+ circuitmux_free(dummy_channel.cmux);
+ testing_disable_reproducible_rng();
+}
+
+/** Just a basic machine whose whole purpose is to reach the END state */
+static void
+helper_create_ender_machine(void)
+{
+ /* Start, burst */
+ circpad_machine_states_init(&circ_client_machine, 2);
+
+ circ_client_machine.states[CIRCPAD_STATE_START].
+ next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_END;
+
+ circ_client_machine.conditions.apply_state_mask = CIRCPAD_STATE_ALL;
+ circ_client_machine.conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
+}
+
+static time_t mocked_timeofday;
+/** Set timeval to a mock date and time. This is necessary
+ * to make tor_gettimeofday() mockable. */
+static void
+mock_tor_gettimeofday(struct timeval *timeval)
+{
+ timeval->tv_sec = mocked_timeofday;
+ timeval->tv_usec = 0;
+}
+
+/** Test manual managing of circuit lifetimes by the circuitpadding
+ * subsystem. In particular this test goes through all the cases of the
+ * circpad_marked_circuit_for_padding() function, via
+ * circuit_mark_for_close() as well as
+ * circuit_expire_old_circuits_clientside(). */
+static void
+test_circuitpadding_manage_circuit_lifetime(void *arg)
+{
+ circpad_machine_runtime_t *mi;
+
+ (void) arg;
+
+ client_side = (circuit_t *)origin_circuit_new();
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ monotime_enable_test_mocking();
+ MOCK(tor_gettimeofday, mock_tor_gettimeofday);
+ mocked_timeofday = 23;
+
+ helper_create_ender_machine();
+
+ /* Enable manual circuit lifetime manage for this test */
+ circ_client_machine.manage_circ_lifetime = 1;
+
+ /* Test setup */
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(client_side, 0);
+ mi = client_side->padding_info[0];
+
+ tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_START);
+
+ /* Check that the circuit is not marked for close */
+ tt_int_op(client_side->marked_for_close, OP_EQ, 0);
+ tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
+
+ /* Mark this circuit for close due to a remote reason */
+ circuit_mark_for_close(client_side,
+ END_CIRC_REASON_FLAG_REMOTE|END_CIRC_REASON_NONE);
+ tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
+ tt_int_op(client_side->marked_for_close, OP_NE, 0);
+ tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
+ client_side->marked_for_close = 0;
+
+ /* Mark this circuit for close due to a protocol issue */
+ circuit_mark_for_close(client_side, END_CIRC_REASON_TORPROTOCOL);
+ tt_int_op(client_side->marked_for_close, OP_NE, 0);
+ tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
+ client_side->marked_for_close = 0;
+
+ /* Mark a measurement circuit for close */
+ client_side->purpose = CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT;
+ circuit_mark_for_close(client_side, END_CIRC_REASON_NONE);
+ tt_int_op(client_side->marked_for_close, OP_NE, 0);
+ tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT);
+ client_side->marked_for_close = 0;
+
+ /* Mark a general circuit for close */
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ circuit_mark_for_close(client_side, END_CIRC_REASON_NONE);
+
+ /* Check that this circuit is still not marked for close since we are
+ * managing the lifetime manually, but the circuit was tagged as such by the
+ * circpadding subsystem */
+ tt_int_op(client_side->marked_for_close, OP_EQ, 0);
+ tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_CIRCUIT_PADDING);
+
+ /* We just tested case (1) from the comments of
+ * circpad_circuit_should_be_marked_for_close() */
+
+ /* Transition the machine to the END state but did not delete its machine */
+ tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
+ circpad_cell_event_nonpadding_received(client_side);
+ tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
+
+ /* We just tested case (3) from the comments of
+ * circpad_circuit_should_be_marked_for_close().
+ * Now let's go for case (2). */
+
+ /* Reset the close mark */
+ client_side->marked_for_close = 0;
+
+ /* Mark this circuit for close */
+ circuit_mark_for_close(client_side, 0);
+
+ /* See that the circ got closed since we are already in END state */
+ tt_int_op(client_side->marked_for_close, OP_NE, 0);
+
+ /* We just tested case (2). Now let's see that case (4) is unreachable as
+ that comment claims */
+
+ /* First, reset all close marks and tags */
+ client_side->marked_for_close = 0;
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ /* Now re-create the ender machine so that we can transition to END again */
+ /* Free up some stuff first */
+ circpad_circuit_free_all_machineinfos(client_side);
+ tor_free(circ_client_machine.states);
+ helper_create_ender_machine();
+
+ client_side->padding_machine[0] = &circ_client_machine;
+ client_side->padding_info[0] =
+ circpad_circuit_machineinfo_new(client_side, 0);
+ mi = client_side->padding_info[0];
+
+ /* Check we are in START. */
+ tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_START);
+
+ /* Test that we don't expire this circuit yet */
+ client_side->timestamp_dirty = 0;
+ client_side->state = CIRCUIT_STATE_OPEN;
+ tor_gettimeofday(&client_side->timestamp_began);
+ TO_ORIGIN_CIRCUIT(client_side)->circuit_idle_timeout = 23;
+ mocked_timeofday += 24;
+ circuit_expire_old_circuits_clientside();
+ circuit_expire_old_circuits_clientside();
+ circuit_expire_old_circuits_clientside();
+ tt_int_op(client_side->timestamp_dirty, OP_NE, 0);
+ tt_int_op(client_side->marked_for_close, OP_EQ, 0);
+ tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_CIRCUIT_PADDING);
+
+ /* Runaway circpad test: if the machine does not transition to end,
+ * test that after CIRCPAD_DELAY_MAX_SECS, we get marked anyway */
+ mocked_timeofday = client_side->timestamp_dirty
+ + get_options()->MaxCircuitDirtiness + 2;
+ client_side->padding_info[0]->last_cell_time_sec =
+ approx_time()-(CIRCPAD_DELAY_MAX_SECS+10);
+ circuit_expire_old_circuits_clientside();
+ tt_int_op(client_side->marked_for_close, OP_NE, 0);
+
+ /* Test back to normal: if we had activity, we won't close */
+ client_side->padding_info[0]->last_cell_time_sec = approx_time();
+ client_side->marked_for_close = 0;
+ circuit_expire_old_circuits_clientside();
+ tt_int_op(client_side->marked_for_close, OP_EQ, 0);
+
+ /* Transition to END, but before we're past the dirty timer */
+ mocked_timeofday = client_side->timestamp_dirty;
+ circpad_cell_event_nonpadding_received(client_side);
+ tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
+
+ /* Verify that the circuit was not closed. */
+ tt_int_op(client_side->marked_for_close, OP_EQ, 0);
+
+ /* Now that we are in END state, we can be closed by expiry, but via
+ * the timestamp_dirty path, not the idle path. So first test not dirty
+ * enough. */
+ mocked_timeofday = client_side->timestamp_dirty;
+ circuit_expire_old_circuits_clientside();
+ tt_int_op(client_side->marked_for_close, OP_EQ, 0);
+ mocked_timeofday = client_side->timestamp_dirty
+ + get_options()->MaxCircuitDirtiness + 2;
+ circuit_expire_old_circuits_clientside();
+ tt_int_op(client_side->marked_for_close, OP_NE, 0);
+
+ done:
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+ tor_free(circ_client_machine.states);
+ monotime_disable_test_mocking();
+ UNMOCK(tor_gettimeofday);
+}
+
+/** Helper for the test_circuitpadding_hs_machines test:
+ *
+ * - Create a client and relay circuit.
+ * - Setup right circuit purpose and attach a machine to the client circuit.
+ * - Verify that state transitions work as intended and state length gets
+ * enforced.
+ *
+ * This function is able to do this test both for intro and rend circuits
+ * depending on the value of <b>test_intro_circs</b>.
+ */
+static void
+helper_test_hs_machines(bool test_intro_circs)
+{
+ /* Setup the circuits */
+ origin_circuit_t *origin_client_side = origin_circuit_new();
+ client_side = TO_CIRCUIT(origin_client_side);
+ client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ dummy_channel.cmux = circuitmux_alloc();
+ relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
+ relay_side->purpose = CIRCUIT_PURPOSE_OR;
+
+ /* extend the client circ to two hops */
+ simulate_single_hop_extend(client_side, relay_side, 1);
+ simulate_single_hop_extend(client_side, relay_side, 1);
+
+ /* machines only apply on opened circuits */
+ origin_client_side->has_opened = 1;
+
+ /************************************/
+
+ /* Attaching the client machine now won't work here because of a wrong
+ * purpose */
+ tt_assert(!client_side->padding_machine[0]);
+ circpad_add_matching_machines(origin_client_side, origin_padding_machines);
+ tt_assert(!client_side->padding_machine[0]);
+
+ /* Change the purpose, see the machine getting attached */
+ client_side->purpose = test_intro_circs ?
+ CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT : CIRCUIT_PURPOSE_C_REND_JOINED;
+ circpad_add_matching_machines(origin_client_side, origin_padding_machines);
+ tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
+ tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
+
+ tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
+ tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
+
+ /* Verify that the right machine is attached */
+ tt_str_op(client_side->padding_machine[0]->name, OP_EQ,
+ test_intro_circs ? "client_ip_circ" : "client_rp_circ");
+ tt_str_op(relay_side->padding_machine[0]->name, OP_EQ,
+ test_intro_circs ? "relay_ip_circ": "relay_rp_circ");
+
+ /***********************************/
+
+ /* Intro machines are at START state, but rend machines have already skipped
+ * to OBFUSCATE_CIRC_SETUP because of the sent PADDING_NEGOTIATE. */
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
+ tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
+
+ /*Send non-padding to move the machines from START to OBFUSCATE_CIRC_SETUP */
+ circpad_cell_event_nonpadding_received(client_side);
+ circpad_cell_event_nonpadding_received(relay_side);
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
+ tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
+
+ /* Check that the state lengths have been sampled and are within range */
+ circpad_machine_runtime_t *client_machine_runtime =
+ client_side->padding_info[0];
+ circpad_machine_runtime_t *relay_machine_runtime =
+ relay_side->padding_info[0];
+
+ if (test_intro_circs) {
+ /* on the client side, we don't send any padding so
+ * state length is not set */
+ tt_i64_op(client_machine_runtime->state_length, OP_EQ, -1);
+ /* relay side has state limits. check them */
+ tt_i64_op(relay_machine_runtime->state_length, OP_GE,
+ INTRO_MACHINE_MINIMUM_PADDING);
+ tt_i64_op(relay_machine_runtime->state_length, OP_LT,
+ INTRO_MACHINE_MAXIMUM_PADDING);
+ } else {
+ tt_i64_op(client_machine_runtime->state_length, OP_EQ, 1);
+ tt_i64_op(relay_machine_runtime->state_length, OP_EQ, 1);
+ }
+
+ if (test_intro_circs) {
+ int i;
+ /* Send state_length worth of padding from the relay and see that the
+ * client state goes to END */
+ for (i = (int) relay_machine_runtime->state_length ; i > 0 ; i--) {
+ circpad_send_padding_cell_for_callback(relay_machine_runtime);
+ }
+ /* See that the machine has been teared down after all the length has been
+ * exhausted (the padding info should now be null on both sides) */
+ tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
+ tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
+ } else {
+ int i;
+ /* Send state_length worth of padding and see that the state goes to END */
+ for (i = (int) client_machine_runtime->state_length ; i > 0 ; i--) {
+ circpad_send_padding_cell_for_callback(client_machine_runtime);
+ }
+ /* See that the machine has been teared down after all the length has been
+ * exhausted. */
+ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
+ CIRCPAD_STATE_END);
+ }
+
+ done:
+ free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
+ circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
+ circuitmux_free(dummy_channel.cmux);
+ free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+}
+
+/** Test that the HS circuit padding machines work as intended. */
+static void
+test_circuitpadding_hs_machines(void *arg)
+{
+ (void)arg;
+
+ /* Test logic:
+ *
+ * 1) Register the HS machines, which aim to hide the presence of
+ * onion service traffic on the client-side
+ *
+ * 2) Call helper_test_hs_machines() to perform tests for the intro circuit
+ * machines and for the rend circuit machines.
+ */
+
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+ MOCK(circuit_package_relay_cell, circuit_package_relay_cell_mock);
+ MOCK(circuit_get_nth_node, circuit_get_nth_node_mock);
+ MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+
+ origin_padding_machines = smartlist_new();
+ relay_padding_machines = smartlist_new();
+
+ nodes_init();
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ monotime_set_mock_time_nsec(1*TOR_NSEC_PER_USEC);
+ monotime_coarse_set_mock_time_nsec(1*TOR_NSEC_PER_USEC);
+ curr_mocked_time = 1*TOR_NSEC_PER_USEC;
+
+ timers_initialize();
+
+ /* This is needed so that we are not considered to be dormant */
+ note_user_activity(20);
+
+ /************************************/
+
+ /* Register the HS machines */
+ circpad_machine_client_hide_intro_circuits(origin_padding_machines);
+ circpad_machine_client_hide_rend_circuits(origin_padding_machines);
+ circpad_machine_relay_hide_intro_circuits(relay_padding_machines);
+ circpad_machine_relay_hide_rend_circuits(relay_padding_machines);
+
+ /***********************************/
+
+ /* Do the tests for the intro circuit machines */
+ helper_test_hs_machines(true);
+ /* Do the tests for the rend circuit machines */
+ helper_test_hs_machines(false);
+
+ timers_shutdown();
+ monotime_disable_test_mocking();
+
+ SMARTLIST_FOREACH_BEGIN(origin_padding_machines,
+ circpad_machine_spec_t *, m) {
+ machine_spec_free(m);
+ } SMARTLIST_FOREACH_END(m);
+
+ SMARTLIST_FOREACH_BEGIN(relay_padding_machines,
+ circpad_machine_spec_t *, m) {
+ machine_spec_free(m);
+ } SMARTLIST_FOREACH_END(m);
+
+ smartlist_free(origin_padding_machines);
+ smartlist_free(relay_padding_machines);
+
+ UNMOCK(circuitmux_attach_circuit);
+ UNMOCK(circuit_package_relay_cell);
+ UNMOCK(circuit_get_nth_node);
+ UNMOCK(circpad_machine_schedule_padding);
+}
+
+/** Test that we effectively ignore non-padding cells in padding circuits. */
+static void
+test_circuitpadding_ignore_non_padding_cells(void *arg)
+{
+ int retval;
+ relay_header_t rh;
+
+ (void) arg;
+
+ client_side = (circuit_t *)origin_circuit_new();
+ client_side->purpose = CIRCUIT_PURPOSE_C_CIRCUIT_PADDING;
+
+ rh.command = RELAY_COMMAND_BEGIN;
+
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = handle_relay_cell_command(NULL, client_side, NULL, NULL, &rh, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ expect_log_msg_containing("Ignored cell");
+
+ done:
+ ;
+}
+
+#define TEST_CIRCUITPADDING(name, flags) \
+ { #name, test_##name, (flags), NULL, NULL }
+
+struct testcase_t circuitpadding_tests[] = {
+ TEST_CIRCUITPADDING(circuitpadding_tokens, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_state_length, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_negotiation, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_wronghop, TT_FORK),
+ /** Disabled unstable test until #29298 is implemented (see #29122) */
+ // TEST_CIRCUITPADDING(circuitpadding_circuitsetup_machine, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_conditions, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_rtt, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_sample_distribution, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_machine_rate_limiting, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_global_rate_limiting, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_reduce_disable, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_token_removal_lower, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_token_removal_higher, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_closest_token_removal, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_closest_token_removal_usec, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_token_removal_exact, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_manage_circuit_lifetime, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_hs_machines, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_ignore_non_padding_cells, TT_FORK),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_circuitstats.c b/src/test/test_circuitstats.c
index 1cbcb14f2b..00ca1b544c 100644
--- a/src/test/test_circuitstats.c
+++ b/src/test/test_circuitstats.c
@@ -1,10 +1,10 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITBUILD_PRIVATE
#define CIRCUITSTATS_PRIVATE
#define CIRCUITLIST_PRIVATE
-#define CHANNEL_PRIVATE_
+#define CHANNEL_FILE_PRIVATE
#include "core/or/or.h"
#include "test/test.h"
@@ -17,18 +17,13 @@
#include "core/or/circuituse.h"
#include "core/or/channel.h"
-#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
#include "core/or/extend_info_st.h"
#include "core/or/origin_circuit_st.h"
-void test_circuitstats_timeout(void *arg);
-void test_circuitstats_hoplen(void *arg);
-origin_circuit_t *subtest_fourhop_circuit(struct timeval, int);
-origin_circuit_t *add_opened_threehop(void);
-origin_circuit_t *build_unopened_fourhop(struct timeval);
-
-int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
+static origin_circuit_t *add_opened_threehop(void);
+static origin_circuit_t *build_unopened_fourhop(struct timeval);
+static origin_circuit_t *subtest_fourhop_circuit(struct timeval, int);
static int marked_for_close;
/* Mock function because we are not trying to test the close circuit that does
@@ -45,85 +40,71 @@ mock_circuit_mark_for_close(circuit_t *circ, int reason, int line,
return;
}
-origin_circuit_t *
+static origin_circuit_t *
add_opened_threehop(void)
{
- origin_circuit_t *or_circ = origin_circuit_new();
+ struct timeval circ_start_time;
+ memset(&circ_start_time, 0, sizeof(circ_start_time));
extend_info_t fakehop;
memset(&fakehop, 0, sizeof(fakehop));
-
- TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
-
- or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
- or_circ->build_state->desired_path_len = DEFAULT_ROUTE_LEN;
-
- onion_append_hop(&or_circ->cpath, &fakehop);
- onion_append_hop(&or_circ->cpath, &fakehop);
- onion_append_hop(&or_circ->cpath, &fakehop);
-
- or_circ->has_opened = 1;
- TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
- TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
-
- return or_circ;
+ extend_info_t *fakehop_list[DEFAULT_ROUTE_LEN] = {&fakehop,
+ &fakehop,
+ &fakehop};
+
+ return new_test_origin_circuit(true,
+ circ_start_time,
+ DEFAULT_ROUTE_LEN,
+ fakehop_list);
}
-origin_circuit_t *
+static origin_circuit_t *
build_unopened_fourhop(struct timeval circ_start_time)
{
- origin_circuit_t *or_circ = origin_circuit_new();
- extend_info_t *fakehop = tor_malloc_zero(sizeof(extend_info_t));
- memset(fakehop, 0, sizeof(extend_info_t));
-
- TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
- TO_CIRCUIT(or_circ)->timestamp_began = circ_start_time;
- TO_CIRCUIT(or_circ)->timestamp_created = circ_start_time;
-
- or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
- or_circ->build_state->desired_path_len = 4;
-
- onion_append_hop(&or_circ->cpath, fakehop);
- onion_append_hop(&or_circ->cpath, fakehop);
- onion_append_hop(&or_circ->cpath, fakehop);
- onion_append_hop(&or_circ->cpath, fakehop);
-
- tor_free(fakehop);
-
- return or_circ;
+ extend_info_t fakehop;
+ memset(&fakehop, 0, sizeof(fakehop));
+ extend_info_t *fakehop_list[4] = {&fakehop,
+ &fakehop,
+ &fakehop,
+ &fakehop};
+
+ return new_test_origin_circuit(false,
+ circ_start_time,
+ 4,
+ fakehop_list);
}
-origin_circuit_t *
+static origin_circuit_t *
subtest_fourhop_circuit(struct timeval circ_start_time, int should_timeout)
{
- origin_circuit_t *or_circ = build_unopened_fourhop(circ_start_time);
+ origin_circuit_t *origin_circ = build_unopened_fourhop(circ_start_time);
// Now make them open one at a time and call
// circuit_build_times_handle_completed_hop();
- or_circ->cpath->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 0);
- or_circ->cpath->next->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->next->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 0);
// Third hop: We should count it now.
- or_circ->cpath->next->next->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->next->next->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ,
!should_timeout); // 1 if counted, 0 otherwise
// Fourth hop: Don't double count
- or_circ->cpath->next->next->next->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->next->next->next->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ,
!should_timeout);
done:
- return or_circ;
+ return origin_circ;
}
-void
+static void
test_circuitstats_hoplen(void *arg)
{
/* Plan:
@@ -197,7 +178,7 @@ test_circuitstats_hoplen(void *arg)
}
#define TEST_CIRCUITSTATS(name, flags) \
- { #name, test_##name, (flags), NULL, NULL }
+ { #name, test_##name, (flags), &helper_pubsub_setup, NULL }
struct testcase_t circuitstats_tests[] = {
TEST_CIRCUITSTATS(circuitstats_hoplen, TT_FORK),
diff --git a/src/test/test_circuituse.c b/src/test/test_circuituse.c
index 3acfc12044..49438d9d3b 100644
--- a/src/test/test_circuituse.c
+++ b/src/test/test_circuituse.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITLIST_PRIVATE
diff --git a/src/test/test_cmdline.sh b/src/test/test_cmdline.sh
new file mode 100755
index 0000000000..ded58af63d
--- /dev/null
+++ b/src/test/test_cmdline.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+umask 077
+set -e
+
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
+# find the tor binary
+if [ $# -ge 1 ]; then
+ TOR_BINARY="${1}"
+ shift
+else
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+die() { echo "$1" >&2 ; exit 5; }
+
+echo "A"
+
+DATA_DIR=$(mktemp -d -t tor_cmdline_tests.XXXXXX)
+trap 'rm -rf "$DATA_DIR"' 0
+
+# 1. Test list-torrc-options.
+OUT="${DATA_DIR}/output"
+
+echo "B"
+"${TOR_BINARY}" --list-torrc-options > "$OUT"
+
+echo "C"
+
+# regular options are given.
+grep -i "SocksPort" "$OUT" >/dev/null || die "Did not find SocksPort"
+
+
+echo "D"
+
+# unlisted options are given, since they do not have the NOSET flag.
+grep -i "__SocksPort" "$OUT" > /dev/null || die "Did not find __SocksPort"
+
+echo "E"
+
+# unsettable options are not given.
+if grep -i "DisableIOCP" "$OUT" /dev/null; then
+ die "Found DisableIOCP"
+fi
+if grep -i "HiddenServiceOptions" "$OUT" /dev/null ; then
+ die "Found HiddenServiceOptions"
+fi
+echo "OK"
diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c
index 2f8646e897..5376e08fb3 100644
--- a/src/test/test_compat_libevent.c
+++ b/src/test/test_compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define COMPAT_LIBEVENT_PRIVATE
@@ -13,8 +13,6 @@
#include "test/log_test_helpers.h"
-#define NS_MODULE compat_libevent
-
static void
test_compat_libevent_logging_callback(void *ignored)
{
@@ -151,8 +149,6 @@ test_compat_libevent_postloop_events(void *arg)
mainloop_event_t *a = NULL, *b = NULL;
periodic_timer_t *timed = NULL;
- tor_libevent_postfork();
-
/* If postloop events don't work, then these events will activate one
* another ad infinitum and, and the periodic event will never occur. */
b = mainloop_event_postloop_new(activate_event_cb, &a);
@@ -187,4 +183,3 @@ struct testcase_t compat_libevent_tests[] = {
TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
-
diff --git a/src/test/test_config.c b/src/test/test_config.c
index d648666f6e..655535f704 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -1,11 +1,13 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define CONFIG_PRIVATE
+#define RELAY_CONFIG_PRIVATE
+#define RELAY_TRANSPORT_CONFIG_PRIVATE
#define PT_PRIVATE
#define ROUTERSET_PRIVATE
#include "core/or/or.h"
@@ -16,7 +18,10 @@
#include "core/or/circuitmux_ewma.h"
#include "core/or/circuitbuild.h"
#include "app/config/config.h"
-#include "app/config/confparse.h"
+#include "app/config/resolve_addr.h"
+#include "feature/relay/relay_config.h"
+#include "feature/relay/transport_config.h"
+#include "lib/confmgt/confmgt.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
#include "test/test.h"
@@ -24,6 +29,7 @@
#include "feature/control/control.h"
#include "core/mainloop/cpuworker.h"
#include "feature/dircache/dirserv.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dirauth/dirvote.h"
#include "feature/relay/dns.h"
#include "feature/client/entrynodes.h"
@@ -37,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"
@@ -45,6 +52,8 @@
#include "app/config/statefile.h"
#include "test/test_helpers.h"
+#include "test/resolve_test_helpers.h"
+#include "test/log_test_helpers.h"
#include "feature/dirclient/dir_server_st.h"
#include "core/or/port_cfg_st.h"
@@ -54,6 +63,7 @@
#include "lib/meminfo/meminfo.h"
#include "lib/net/gethostname.h"
#include "lib/encoding/confline.h"
+#include "lib/encoding/kvline.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -398,7 +408,7 @@ good_bridge_line_test(const char *string, const char *test_addrport,
tor_free(tmp);
}
- /* If we were asked to validate a transport name, make sure tha it
+ /* If we were asked to validate a transport name, make sure that it
matches with the transport name that was parsed. */
if (test_transport && !bridge_line->transport_name)
tt_abort();
@@ -670,6 +680,54 @@ transport_is_needed_mock(const char *transport_name)
return transport_is_needed_mock_return;
}
+static void
+test_config_parse_tcp_proxy_line(void *arg)
+{
+ (void)arg;
+
+ int ret;
+ char *msg = NULL;
+ or_options_t *options = get_options_mutable();
+
+ /* Bad TCPProxy line - too short. */
+ ret = parse_tcp_proxy_line("haproxy", options, &msg);
+ /* Return error. */
+ tt_int_op(ret, OP_EQ, -1);
+ /* Correct error message. */
+ tt_str_op(msg, OP_EQ, "TCPProxy has no address/port. Please fix.");
+ /* Free error message. */
+ tor_free(msg);
+
+ /* Bad TCPProxy line - unsupported protocol. */
+ ret = parse_tcp_proxy_line("unsupported 95.216.163.36:443", options, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ, "TCPProxy protocol is not supported. Currently the "
+ "only supported protocol is 'haproxy'. Please fix.");
+ tor_free(msg);
+
+ /* Bad TCPProxy line - unparsable address/port. */
+ MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
+ ret = parse_tcp_proxy_line("haproxy bogus_address!/300", options, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ, "TCPProxy address/port failed to parse or resolve. "
+ "Please fix.");
+ tor_free(msg);
+ UNMOCK(tor_addr_lookup);
+
+ /* Good TCPProxy line - ipv4. */
+ ret = parse_tcp_proxy_line("haproxy 95.216.163.36:443", options, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(options->TCPProxyProtocol, OP_EQ, TCP_PROXY_PROTOCOL_HAPROXY);
+ /* Correct the address. */
+ tt_assert(tor_addr_eq_ipv4h(&options->TCPProxyAddr, 0x5fd8a324));
+ tt_int_op(options->TCPProxyPort, OP_EQ, 443);
+ tor_free(msg);
+
+ done:
+ UNMOCK(tor_addr_lookup);
+}
+
/**
* Test parsing for the ClientTransportPlugin and ServerTransportPlugin config
* options.
@@ -687,84 +745,84 @@ test_config_parse_transport_plugin_line(void *arg)
int old_transport_is_needed_mock_call_count;
/* Bad transport lines - too short */
- r = parse_transport_line(options, "bad", 1, 0);
+ r = pt_parse_transport_line(options, "bad", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options, "bad", 1, 1);
+ r = pt_parse_transport_line(options, "bad", 1, 1);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options, "bad bad", 1, 0);
+ r = pt_parse_transport_line(options, "bad bad", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options, "bad bad", 1, 1);
+ r = pt_parse_transport_line(options, "bad bad", 1, 1);
tt_int_op(r, OP_LT, 0);
/* Test transport list parsing */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 0);
tt_int_op(r, OP_EQ, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 1);
tt_int_op(r, OP_EQ, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1,transport_2 exec /usr/bin/fake-transport", 1, 0);
tt_int_op(r, OP_EQ, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1,transport_2 exec /usr/bin/fake-transport", 1, 1);
tt_int_op(r, OP_EQ, 0);
/* Bad transport identifiers */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_* exec /usr/bin/fake-transport", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_* exec /usr/bin/fake-transport", 1, 1);
tt_int_op(r, OP_LT, 0);
/* Check SOCKS cases for client transport */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 socks4 1.2.3.4:567", 1, 0);
tt_int_op(r, OP_EQ, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 socks5 1.2.3.4:567", 1, 0);
tt_int_op(r, OP_EQ, 0);
/* Proxy case for server transport */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 proxy 1.2.3.4:567", 1, 1);
tt_int_op(r, OP_EQ, 0);
/* Multiple-transport error exit */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1,transport_2 socks5 1.2.3.4:567", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1,transport_2 proxy 1.2.3.4:567", 1, 1);
tt_int_op(r, OP_LT, 0);
/* No port error exit */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 socks5 1.2.3.4", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 proxy 1.2.3.4", 1, 1);
tt_int_op(r, OP_LT, 0);
/* Unparsable address error exit */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 socks5 1.2.3:6x7", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 proxy 1.2.3:6x7", 1, 1);
tt_int_op(r, OP_LT, 0);
/* "Strange {Client|Server}TransportPlugin field" error exit */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 foo bar", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 foo bar", 1, 1);
tt_int_op(r, OP_LT, 0);
/* No sandbox mode error exit */
tmp = options->Sandbox;
options->Sandbox = 1;
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 0);
tt_int_op(r, OP_LT, 0);
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 1);
tt_int_op(r, OP_LT, 0);
options->Sandbox = tmp;
@@ -776,7 +834,7 @@ test_config_parse_transport_plugin_line(void *arg)
MOCK(pt_kickstart_proxy, pt_kickstart_proxy_mock);
old_pt_kickstart_proxy_mock_call_count =
pt_kickstart_proxy_mock_call_count;
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 0, 1);
tt_int_op(r, OP_EQ, 0);
tt_assert(pt_kickstart_proxy_mock_call_count ==
@@ -784,7 +842,7 @@ test_config_parse_transport_plugin_line(void *arg)
UNMOCK(pt_kickstart_proxy);
/* This one hits a log line in the !validate_only case only */
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 proxy 1.2.3.4:567", 0, 1);
tt_int_op(r, OP_EQ, 0);
@@ -801,7 +859,7 @@ test_config_parse_transport_plugin_line(void *arg)
transport_add_from_config_mock_call_count;
old_transport_is_needed_mock_call_count =
transport_is_needed_mock_call_count;
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 0, 0);
/* Should have succeeded */
tt_int_op(r, OP_EQ, 0);
@@ -825,7 +883,7 @@ test_config_parse_transport_plugin_line(void *arg)
transport_add_from_config_mock_call_count;
old_transport_is_needed_mock_call_count =
transport_is_needed_mock_call_count;
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 0, 0);
/* Should have succeeded */
tt_int_op(r, OP_EQ, 0);
@@ -849,7 +907,7 @@ test_config_parse_transport_plugin_line(void *arg)
transport_add_from_config_mock_call_count;
old_transport_is_needed_mock_call_count =
transport_is_needed_mock_call_count;
- r = parse_transport_line(options,
+ r = pt_parse_transport_line(options,
"transport_1 socks5 1.2.3.4:567", 0, 0);
/* Should have succeeded */
tt_int_op(r, OP_EQ, 0);
@@ -904,14 +962,12 @@ test_config_fix_my_family(void *arg)
family3->next = NULL;
or_options_t* options = options_new();
- or_options_t* defaults = options_new();
(void) arg;
options_init(options);
- options_init(defaults);
options->MyFamily_lines = family;
- options_validate(NULL, options, defaults, 0, &err) ;
+ options_validate(NULL, options, &err) ;
if (err != NULL) {
TT_FAIL(("options_validate failed: %s", err));
@@ -933,57 +989,75 @@ test_config_fix_my_family(void *arg)
done:
tor_free(err);
or_options_free(options);
- or_options_free(defaults);
}
static int n_hostname_01010101 = 0;
+static const char *ret_addr_lookup_01010101[2] = {
+ "1.1.1.1", "0101::0101",
+};
-/** This mock function is meant to replace tor_lookup_hostname().
- * It answers with 1.1.1.1 as IP adddress that resulted from lookup.
+/** This mock function is meant to replace tor_addr_lookup().
+ * It answers with 1.1.1.1 as IP address that resulted from lookup.
* This function increments <b>n_hostname_01010101</b> counter by one
* every time it is called.
*/
static int
-tor_lookup_hostname_01010101(const char *name, uint32_t *addr)
+tor_addr_lookup_01010101(const char *name, uint16_t family, tor_addr_t *addr)
{
n_hostname_01010101++;
- if (name && addr) {
- *addr = ntohl(0x01010101);
+ if (family == AF_INET) {
+ if (name && addr) {
+ int ret = tor_addr_parse(addr, ret_addr_lookup_01010101[0]);
+ tt_int_op(ret, OP_EQ, family);
+ }
+ } else if (family == AF_INET6) {
+ if (name && addr) {
+ int ret = tor_addr_parse(addr, ret_addr_lookup_01010101[1]);
+ tt_int_op(ret, OP_EQ, family);
+ }
}
-
+ done:
return 0;
}
static int n_hostname_localhost = 0;
-/** This mock function is meant to replace tor_lookup_hostname().
- * It answers with 127.0.0.1 as IP adddress that resulted from lookup.
+/** This mock function is meant to replace tor_addr_lookup().
+ * It answers with 127.0.0.1 as IP address that resulted from lookup.
* This function increments <b>n_hostname_localhost</b> counter by one
* every time it is called.
*/
static int
-tor_lookup_hostname_localhost(const char *name, uint32_t *addr)
+tor_addr_lookup_localhost(const char *name, uint16_t family, tor_addr_t *addr)
{
n_hostname_localhost++;
- if (name && addr) {
- *addr = 0x7f000001;
+ if (family == AF_INET) {
+ if (name && addr) {
+ tor_addr_from_ipv4h(addr, 0x7f000001);
+ }
+ } else if (family == AF_INET6) {
+ if (name && addr) {
+ int ret = tor_addr_parse(addr, "::1");
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ }
}
-
+ done:
return 0;
}
static int n_hostname_failure = 0;
-/** This mock function is meant to replace tor_lookup_hostname().
+/** This mock function is meant to replace tor_addr_lookup().
* It pretends to fail by returning -1 to caller. Also, this function
* increments <b>n_hostname_failure</b> every time it is called.
*/
static int
-tor_lookup_hostname_failure(const char *name, uint32_t *addr)
+tor_addr_lookup_failure(const char *name, uint16_t family, tor_addr_t *addr)
{
(void)name;
+ (void)family;
(void)addr;
n_hostname_failure++;
@@ -991,6 +1065,46 @@ tor_lookup_hostname_failure(const char *name, uint32_t *addr)
return -1;
}
+/** Mock function for tor_addr_lookup().
+ *
+ * Depending on the given hostname and family, resolve either to IPv4 or IPv6.
+ *
+ * If the requested hostname family is not the same as the family provided, an
+ * error is returned.
+ *
+ * Possible hostnames:
+ * - www.torproject.org.v4 for IPv4 -> 1.1.1.1
+ * - www.torproject.org.v6 for IPv6 -> [0101::0101]
+ */
+static int
+tor_addr_lookup_mixed(const char *name, uint16_t family, tor_addr_t *addr)
+{
+ tt_assert(addr);
+ tt_assert(name);
+
+ if (!strcmp(name, "www.torproject.org.v4")) {
+ if (family == AF_INET) {
+ tor_addr_from_ipv4h(addr, 0x01010101);
+ return 0;
+ }
+ /* Resolving AF_INET but the asked family is different. Failure. */
+ return -1;
+ }
+
+ if (!strcmp(name, "www.torproject.org.v6")) {
+ if (family == AF_INET6) {
+ int ret = tor_addr_parse(addr, "0101::0101");
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ return 0;
+ }
+ /* Resolving AF_INET6 but the asked family is not. Failure. */
+ return -1;
+ }
+
+ done:
+ return 0;
+}
+
static int n_gethostname_replacement = 0;
/** This mock function is meant to replace tor_gethostname(). It
@@ -1045,29 +1159,39 @@ tor_gethostname_failure(char *name, size_t namelen)
return -1;
}
-static int n_get_interface_address = 0;
+static int n_get_interface_address6 = 0;
+static sa_family_t last_address6_family;
+static const char *ret_get_interface_address6_08080808[2] = {
+ "8.8.8.8", "0808::0808",
+};
/** This mock function is meant to replace get_interface_address().
* It answers with address 8.8.8.8. This function increments
* <b>n_get_interface_address</b> by one every time it is called.
*/
static int
-get_interface_address_08080808(int severity, uint32_t *addr)
+get_interface_address6_08080808(int severity, sa_family_t family,
+ tor_addr_t *addr)
{
(void)severity;
- n_get_interface_address++;
+ n_get_interface_address6++;
- if (addr) {
- *addr = ntohl(0x08080808);
+ if (family == AF_INET) {
+ if (addr) {
+ int ret = tor_addr_parse(addr, ret_get_interface_address6_08080808[0]);
+ tt_int_op(ret, OP_EQ, AF_INET);
+ }
+ } else if (family == AF_INET6) {
+ if (addr) {
+ int ret = tor_addr_parse(addr, ret_get_interface_address6_08080808[1]);
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ }
}
-
+ done:
return 0;
}
-static int n_get_interface_address6 = 0;
-static sa_family_t last_address6_family;
-
/** This mock function is meant to replace get_interface_address6().
* It answers with IP address 9.9.9.9 iff both of the following are true:
* - <b>family</b> is AF_INET
@@ -1075,6 +1199,7 @@ static sa_family_t last_address6_family;
* This function increments <b>n_get_interface_address6</b> by one every
* time it is called.
*/
+#if 0
static int
get_interface_address6_replacement(int severity, sa_family_t family,
tor_addr_t *addr)
@@ -1092,25 +1217,7 @@ get_interface_address6_replacement(int severity, sa_family_t family,
return 0;
}
-
-static int n_get_interface_address_failure = 0;
-
-/**
- * This mock function is meant to replace get_interface_address().
- * It pretends to fail getting interface address by returning -1.
- * <b>n_get_interface_address_failure</b> is incremented by one
- * every time this function is called.
- */
-static int
-get_interface_address_failure(int severity, uint32_t *addr)
-{
- (void)severity;
- (void)addr;
-
- n_get_interface_address_failure++;
-
- return -1;
-}
+#endif
static int n_get_interface_address6_failure = 0;
@@ -1133,24 +1240,44 @@ get_interface_address6_failure(int severity, sa_family_t family,
return -1;
}
+/** Helper macro: to validate the returned value from find_my_address() so we
+ * don't copy those all the time. */
+#undef VALIDATE_FOUND_ADDRESS
+#define VALIDATE_FOUND_ADDRESS(ret, method, hostname) \
+ do { \
+ tt_int_op(retval, OP_EQ, ret); \
+ tt_int_op(method, OP_EQ, method_used); \
+ if (hostname == NULL) tt_assert(!hostname_out); \
+ else tt_str_op(hostname_out, OP_EQ, hostname); \
+ if (ret == true) { \
+ tt_assert(tor_addr_eq(&resolved_addr, &test_addr)); \
+ } \
+ } while (0)
+
+/** Helper macro: Cleanup the address and variables used after a
+ * find_my_address() call. */
+#undef CLEANUP_FOUND_ADDRESS
+#define CLEANUP_FOUND_ADDRESS \
+ do { \
+ config_free_lines(options->Address); \
+ config_free_lines(options->ORPort_lines); \
+ options->AddressDisableIPv6 = 0; \
+ options->ORPort_set = 0; \
+ tor_free(options->DirAuthorities); \
+ tor_free(hostname_out); \
+ tor_addr_make_unspec(&resolved_addr); \
+ tor_addr_make_unspec(&test_addr); \
+ } while (0)
+
+/** Test both IPv4 and IPv6 coexisting together in the configuration. */
static void
-test_config_resolve_my_address(void *arg)
+test_config_find_my_address_mixed(void *arg)
{
or_options_t *options;
- uint32_t resolved_addr;
- const char *method_used;
+ tor_addr_t resolved_addr, test_addr;
+ resolved_addr_method_t method_used;
char *hostname_out = NULL;
- int retval;
- int prev_n_hostname_01010101;
- int prev_n_hostname_localhost;
- int prev_n_hostname_failure;
- int prev_n_gethostname_replacement;
- int prev_n_gethostname_failure;
- int prev_n_gethostname_localhost;
- int prev_n_get_interface_address;
- int prev_n_get_interface_address_failure;
- int prev_n_get_interface_address6;
- int prev_n_get_interface_address6_failure;
+ bool retval;
(void)arg;
@@ -1158,369 +1285,530 @@ test_config_resolve_my_address(void *arg)
options_init(options);
- /*
- * CASE 1:
- * If options->Address is a valid IPv4 address string, we want
- * the corresponding address to be parsed and returned.
- */
-
- options->Address = tor_strdup("128.52.128.105");
+ /*
+ * CASE 1: Only IPv6 address. Accepted.
+ */
+ config_line_append(&options->Address, "Address",
+ "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
+ tor_addr_parse(&test_addr, "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /* IPv6 address should be found and considered configured. */
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
- tt_want(retval == 0);
- tt_want_str_op(method_used,OP_EQ,"CONFIGURED");
- tt_want(hostname_out == NULL);
- tt_assert(resolved_addr == 0x80348069);
+ CLEANUP_FOUND_ADDRESS;
- tor_free(options->Address);
+ /*
+ * Case 2: IPv4 _and_ IPv6 given. Accepted.
+ */
+ config_line_append(&options->Address, "Address",
+ "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
+ config_line_append(&options->Address, "Address", "1.1.1.1");
+ tor_addr_parse(&test_addr, "1.1.1.1");
-/*
- * CASE 2:
- * If options->Address is a valid DNS address, we want resolve_my_address()
- * function to ask tor_lookup_hostname() for help with resolving it
- * and return the address that was resolved (in host order).
- */
+ /* IPv4 address should be found and considered configured. */
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101);
+ /* IPv6 address should be found and considered configured. */
+ tor_addr_parse(&test_addr, "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
- tor_free(options->Address);
- options->Address = tor_strdup("www.torproject.org");
+ CLEANUP_FOUND_ADDRESS;
- prev_n_hostname_01010101 = n_hostname_01010101;
+ /*
+ * Case 3: Two hostnames, IPv4 and IPv6.
+ */
+ config_line_append(&options->Address, "Address", "www.torproject.org.v4");
+ config_line_append(&options->Address, "Address", "www.torproject.org.v6");
+
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
+
+ /* IPv4 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "1.1.1.1");
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED,
+ "www.torproject.org.v4");
+ tor_free(hostname_out);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /* IPv6 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "0101::0101");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED,
+ "www.torproject.org.v6");
- tt_want(retval == 0);
- tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1);
- tt_want_str_op(method_used,OP_EQ,"RESOLVED");
- tt_want_str_op(hostname_out,OP_EQ,"www.torproject.org");
- tt_assert(resolved_addr == 0x01010101);
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(tor_addr_lookup);
- UNMOCK(tor_lookup_hostname);
+ /*
+ * Case 4: IPv4 address and a hostname resolving to IPV6.
+ */
+ config_line_append(&options->Address, "Address", "1.1.1.1");
+ config_line_append(&options->Address, "Address", "www.torproject.org.v6");
+
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
+
+ /* IPv4 address should be found and configured. */
+ tor_addr_parse(&test_addr, "1.1.1.1");
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
+
+ /* IPv6 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "0101::0101");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED,
+ "www.torproject.org.v6");
+
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(tor_addr_lookup);
- tor_free(options->Address);
+ /*
+ * Case 5: Hostname resolving to IPv4 and an IPv6 address.
+ */
+ config_line_append(&options->Address, "Address", "0101::0101");
+ config_line_append(&options->Address, "Address", "www.torproject.org.v4");
+
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
+
+ /* IPv4 address should be found and resolved. */
+ tor_addr_parse(&test_addr, "1.1.1.1");
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED,
+ "www.torproject.org.v4");
tor_free(hostname_out);
-/*
- * CASE 3:
- * Given that options->Address is NULL, we want resolve_my_address()
- * to try and use tor_gethostname() to get hostname AND use
- * tor_lookup_hostname() to get IP address.
- */
-
- resolved_addr = 0;
- tor_free(options->Address);
- options->Address = NULL;
+ /* IPv6 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "0101::0101");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
+ CLEANUP_FOUND_ADDRESS;
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101);
+ UNMOCK(tor_addr_lookup);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_01010101 = n_hostname_01010101;
+ done:
+ config_free_lines(options->Address);
+ or_options_free(options);
+ tor_free(hostname_out);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ UNMOCK(tor_addr_lookup);
+}
- tt_want(retval == 0);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1);
- tt_want_str_op(method_used,OP_EQ,"GETHOSTNAME");
- tt_want_str_op(hostname_out,OP_EQ,"onionrouter!");
- tt_assert(resolved_addr == 0x01010101);
+/** Parameters for the find_my_address() test. We test both AF_INET and
+ * AF_INET6 but we have one interface to do so thus we run the same exact unit
+ * tests for both without copying them. */
+typedef struct find_my_address_params_t {
+ /* Index where the mock function results are located. For instance,
+ * tor_addr_lookup_01010101() will have its returned value depending on the
+ * family in ret_addr_lookup_01010101[].
+ *
+ * Values that can be found:
+ * AF_INET : index 0.
+ * AF_INET6: index 1.
+ */
+ int idx;
+ int family;
+ const char *public_ip;
+ const char *internal_ip;
+ const char *orport;
+} find_my_address_params_t;
+
+static find_my_address_params_t addr_param_v4 = {
+ .idx = 0,
+ .family = AF_INET,
+ .public_ip = "128.52.128.105",
+ .internal_ip = "127.0.0.1",
+};
- UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
+static find_my_address_params_t addr_param_v6 = {
+ .idx = 1,
+ .family = AF_INET6,
+ .public_ip = "[4242::4242]",
+ .internal_ip = "[::1]",
+};
- tor_free(hostname_out);
+static void
+test_config_find_my_address(void *arg)
+{
+ or_options_t *options;
+ tor_addr_t resolved_addr, test_addr;
+ resolved_addr_method_t method_used;
+ char *hostname_out = NULL;
+ bool retval;
+ int prev_n_hostname_01010101;
+ int prev_n_hostname_failure;
+ int prev_n_hostname_localhost;
+ int prev_n_gethostname_replacement;
+ int prev_n_gethostname_failure;
+ int prev_n_gethostname_localhost;
+ int prev_n_get_interface_address6;
+ int prev_n_get_interface_address6_failure;
-/*
- * CASE 4:
- * Given that options->Address is a local host address, we want
- * resolve_my_address() function to fail.
- */
+ const find_my_address_params_t *p = arg;
- resolved_addr = 0;
- tor_free(options->Address);
- options->Address = tor_strdup("127.0.0.1");
+ options = options_new();
+ options_init(options);
+ options->PublishServerDescriptor_ = V3_DIRINFO;
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /*
+ * Case 0:
+ * AddressDisableIPv6 is set.
+ *
+ * Only run this if we are in the IPv6 test.
+ */
+ if (p->family == AF_INET6) {
+ options->AddressDisableIPv6 = 1;
+ /* Set a valid IPv6. However, the discovery should still fail. */
+ config_line_append(&options->Address, "Address", p->public_ip);
+ tor_addr_parse(&test_addr, p->public_ip);
+
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
+ }
- tt_want(resolved_addr == 0);
- tt_int_op(retval, OP_EQ, -1);
+ /*
+ * Case 1:
+ * 1. Address is a valid address.
+ *
+ * Expected to succeed.
+ */
+ config_line_append(&options->Address, "Address", p->public_ip);
+ tor_addr_parse(&test_addr, p->public_ip);
- tor_free(options->Address);
- tor_free(hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
-/*
- * CASE 5:
- * We want resolve_my_address() to fail if DNS address in options->Address
- * cannot be resolved.
- */
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
+ CLEANUP_FOUND_ADDRESS;
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
+ /*
+ * Case 2: Address is a resolvable address. Expected to succeed.
+ */
+ MOCK(tor_addr_lookup, tor_addr_lookup_01010101);
- prev_n_hostname_failure = n_hostname_failure;
+ config_line_append(&options->Address, "Address", "www.torproject.org");
+ tor_addr_parse(&test_addr, ret_addr_lookup_01010101[p->idx]);
- tor_free(options->Address);
- options->Address = tor_strdup("www.tor-project.org");
+ prev_n_hostname_01010101 = n_hostname_01010101;
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_int_op(retval, OP_EQ, -1);
+ tt_int_op(n_hostname_01010101, OP_EQ, ++prev_n_hostname_01010101);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED, "www.torproject.org");
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(tor_lookup_hostname);
+ UNMOCK(tor_addr_lookup);
- tor_free(options->Address);
- tor_free(hostname_out);
+ /*
+ * Case 3: Address is a local addressi (internal). Expected to fail.
+ */
+ config_line_append(&options->Address, "Address", p->internal_ip);
-/*
- * CASE 6:
- * If options->Address is NULL AND gettting local hostname fails, we want
- * resolve_my_address() to fail as well.
- */
+ setup_full_capture_of_logs(LOG_NOTICE);
- MOCK(tor_gethostname,tor_gethostname_failure);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- prev_n_gethostname_failure = n_gethostname_failure;
+ expect_log_msg_containing("is a private IP address. Tor relays that "
+ "use the default DirAuthorities must have "
+ "public IP addresses.");
+ teardown_capture_of_logs();
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
- tt_want(n_gethostname_failure == prev_n_gethostname_failure + 1);
- tt_int_op(retval, OP_EQ, -1);
+ /*
+ * Case 4: Address is a local address but custom authorities. Expected to
+ * succeed.
+ */
+ config_line_append(&options->Address, "Address", p->internal_ip);
+ options->DirAuthorities = tor_malloc_zero(sizeof(config_line_t));
+ tor_addr_parse(&test_addr, p->internal_ip);
- UNMOCK(tor_gethostname);
- tor_free(hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
-/*
- * CASE 7:
- * We want resolve_my_address() to try and get network interface address via
- * get_interface_address() if hostname returned by tor_gethostname() cannot be
- * resolved into IP address.
- */
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
+ CLEANUP_FOUND_ADDRESS;
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
- MOCK(get_interface_address,get_interface_address_08080808);
+ /*
+ * Case 5: Multiple address in Address. Expected to fail.
+ */
+ config_line_append(&options->Address, "Address", p->public_ip);
+ config_line_append(&options->Address, "Address", p->public_ip);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_get_interface_address = n_get_interface_address;
+ setup_full_capture_of_logs(LOG_NOTICE);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(retval == 0);
- tt_want_int_op(n_gethostname_replacement, OP_EQ,
- prev_n_gethostname_replacement + 1);
- tt_want_int_op(n_get_interface_address, OP_EQ,
- prev_n_get_interface_address + 1);
- tt_want_str_op(method_used,OP_EQ,"INTERFACE");
- tt_want(hostname_out == NULL);
- tt_assert(resolved_addr == 0x08080808);
+ expect_log_msg_containing("Found 2 Address statement of address family");
+ teardown_capture_of_logs();
- UNMOCK(get_interface_address);
- tor_free(hostname_out);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
-/*
- * CASE 8:
- * Suppose options->Address is NULL AND hostname returned by tor_gethostname()
- * is unresolvable. We want resolve_my_address to fail if
- * get_interface_address() fails.
- */
+ /*
+ * Case 8:
+ * 1. Address is NULL
+ * 2. Interface address is a valid address.
+ *
+ * Expected to succeed.
+ */
+ options->Address = NULL;
+ tor_addr_parse(&test_addr, ret_get_interface_address6_08080808[p->idx]);
- MOCK(get_interface_address,get_interface_address_failure);
+ MOCK(get_interface_address6, get_interface_address6_08080808);
- prev_n_get_interface_address_failure = n_get_interface_address_failure;
- prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_get_interface_address6 = n_get_interface_address6;
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_get_interface_address_failure ==
- prev_n_get_interface_address_failure + 1);
- tt_want(n_gethostname_replacement ==
- prev_n_gethostname_replacement + 1);
- tt_int_op(retval, OP_EQ, -1);
+ tt_int_op(n_get_interface_address6, OP_EQ, ++prev_n_get_interface_address6);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_INTERFACE, NULL);
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(get_interface_address);
- tor_free(hostname_out);
+ UNMOCK(get_interface_address6);
-/*
- * CASE 9:
- * Given that options->Address is NULL AND tor_lookup_hostname()
- * fails AND hostname returned by gethostname() resolves
- * to local IP address, we want resolve_my_address() function to
- * call get_interface_address6(.,AF_INET,.) and return IP address
- * the latter function has found.
- */
+ /*
+ * Case 9:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname resolves to a valid address.
+ *
+ * Expected to succeed.
+ */
+ options->Address = NULL;
+ tor_addr_parse(&test_addr, ret_addr_lookup_01010101[p->idx]);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(get_interface_address6,get_interface_address6_replacement);
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_replacement);
+ MOCK(tor_addr_lookup, tor_addr_lookup_01010101);
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_hostname_01010101 = n_hostname_01010101;
prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_failure = n_hostname_failure;
- prev_n_get_interface_address6 = n_get_interface_address6;
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(last_address6_family == AF_INET);
- tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1);
- tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(retval == 0);
- tt_want_str_op(method_used,OP_EQ,"INTERFACE");
- tt_assert(resolved_addr == 0x09090909);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_hostname_01010101, OP_EQ,
+ ++prev_n_hostname_01010101);
+ tt_int_op(n_gethostname_replacement, OP_EQ,
+ ++prev_n_gethostname_replacement);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_GETHOSTNAME, "onionrouter!");
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(tor_lookup_hostname);
- UNMOCK(tor_gethostname);
UNMOCK(get_interface_address6);
-
- tor_free(hostname_out);
+ UNMOCK(tor_gethostname);
+ UNMOCK(tor_addr_lookup);
/*
- * CASE 10: We want resolve_my_address() to fail if all of the following
- * are true:
- * 1. options->Address is not NULL
- * 2. ... but it cannot be converted to struct in_addr by
- * tor_inet_aton()
- * 3. ... and tor_lookup_hostname() fails to resolve the
- * options->Address
+ * Case 10:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname resolves to an internal address.
+ *
+ * Expected to fail.
*/
+ options->Address = NULL;
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
-
- prev_n_hostname_failure = n_hostname_failure;
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_localhost);
+ MOCK(tor_addr_lookup, tor_addr_lookup_localhost);
- tor_free(options->Address);
- options->Address = tor_strdup("some_hostname");
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_hostname_localhost = n_hostname_localhost;
+ prev_n_gethostname_localhost = n_gethostname_localhost;
- retval = resolve_my_address(LOG_NOTICE, options, &resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_int_op(retval, OP_EQ, -1);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_hostname_localhost, OP_EQ,
+ ++prev_n_hostname_localhost);
+ tt_int_op(n_gethostname_localhost, OP_EQ,
+ ++prev_n_gethostname_localhost);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(get_interface_address6);
UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
-
- tor_free(hostname_out);
+ UNMOCK(tor_addr_lookup);
/*
- * CASE 11:
- * Suppose the following sequence of events:
- * 1. options->Address is NULL
- * 2. tor_gethostname() succeeds to get hostname of machine Tor
- * if running on.
- * 3. Hostname from previous step cannot be converted to
- * address by using tor_inet_aton() function.
- * 4. However, tor_lookup_hostname() succeeds in resolving the
- * hostname from step 2.
- * 5. Unfortunately, tor_addr_is_internal() deems this address
- * to be internal.
- * 6. get_interface_address6(.,AF_INET,.) returns non-internal
- * IPv4
+ * Case 11:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname fails to be found.
*
- * We want resolve_my_addr() to succeed with method "INTERFACE"
- * and address from step 6.
+ * Expected to fail.
*/
-
- tor_free(options->Address);
options->Address = NULL;
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_localhost);
- MOCK(get_interface_address6,get_interface_address6_replacement);
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_failure);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_localhost = n_hostname_localhost;
- prev_n_get_interface_address6 = n_get_interface_address6;
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_gethostname_failure = n_gethostname_failure;
- retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1);
- tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_gethostname_failure, OP_EQ,
+ ++prev_n_gethostname_failure);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
- tt_str_op(method_used,OP_EQ,"INTERFACE");
- tt_ptr_op(hostname_out, OP_EQ, NULL);
- tt_int_op(retval, OP_EQ, 0);
+ UNMOCK(get_interface_address6);
+ UNMOCK(tor_gethostname);
/*
- * CASE 11b:
- * 1-5 as above.
- * 6. get_interface_address6() fails.
+ * Case 12:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname can't be resolved.
*
- * In this subcase, we want resolve_my_address() to fail.
+ * Expected to fail.
*/
+ options->Address = NULL;
- UNMOCK(get_interface_address6);
- MOCK(get_interface_address6,get_interface_address6_failure);
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_replacement);
+ MOCK(tor_addr_lookup, tor_addr_lookup_failure);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_localhost = n_hostname_localhost;
prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_hostname_failure = n_hostname_failure;
- retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1);
- tt_want(n_get_interface_address6_failure ==
- prev_n_get_interface_address6_failure + 1);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_gethostname_replacement, OP_EQ,
+ ++prev_n_gethostname_replacement);
+ tt_int_op(n_hostname_failure, OP_EQ,
+ ++prev_n_hostname_failure);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
- tt_int_op(retval, OP_EQ, -1);
+ /*
+ * Case 13:
+ * 1. Address is NULL.
+ * 2. ORPort has a valid public address.
+ */
+ {
+ char *msg = NULL;
+ int n, w, ret;
+ char *orport_line = NULL;
+
+ options->Address = NULL;
+ tor_asprintf(&orport_line, "%s:9001", p->public_ip);
+ config_line_append(&options->ORPort_lines, "ORPort", orport_line);
+ tor_free(orport_line);
+
+ if (p->family == AF_INET6) {
+ /* XXX: Tor does _not_ allow an IPv6 only ORPort thus we need to add a
+ * bogus IPv4 at the moment. */
+ config_line_append(&options->ORPort_lines, "ORPort", "1.1.1.1:9001");
+ }
- UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
- UNMOCK(get_interface_address6);
+ ret = parse_ports(options, 0, &msg, &n, &w);
+ tt_int_op(ret, OP_EQ, 0);
+ tor_addr_parse(&test_addr, p->public_ip);
+ }
- /* CASE 12:
- * Suppose the following happens:
- * 1. options->Address is NULL AND options->DirAuthorities is non-NULL
- * 2. tor_gethostname() succeeds in getting hostname of a machine ...
- * 3. ... which is successfully parsed by tor_inet_aton() ...
- * 4. into IPv4 address that tor_addr_is_inernal() considers to be
- * internal.
- *
- * In this case, we want resolve_my_address() to fail.
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED_ORPORT, NULL);
+ CLEANUP_FOUND_ADDRESS;
+
+ /*
+ * Case 14:
+ * 1. Address is NULL.
+ * 2. ORPort has an internal address thus fails.
+ * 3. Interface as a valid address.
*/
+ {
+ char *msg = NULL;
+ int n, w, ret;
+ char *orport_line = NULL;
+
+ options->Address = NULL;
+ tor_asprintf(&orport_line, "%s:9001", p->internal_ip);
+ config_line_append(&options->ORPort_lines, "ORPort", orport_line);
+ tor_free(orport_line);
+
+ if (p->family == AF_INET6) {
+ /* XXX: Tor does _not_ allow an IPv6 only ORPort thus we need to add a
+ * bogus IPv4 at the moment. */
+ config_line_append(&options->ORPort_lines, "ORPort", "1.1.1.1:9001");
+ }
- tor_free(options->Address);
- options->Address = NULL;
- options->DirAuthorities = tor_malloc_zero(sizeof(config_line_t));
+ ret = parse_ports(options, 0, &msg, &n, &w);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+ tor_addr_parse(&test_addr, ret_get_interface_address6_08080808[p->idx]);
- MOCK(tor_gethostname,tor_gethostname_localhost);
+ MOCK(get_interface_address6, get_interface_address6_08080808);
- prev_n_gethostname_localhost = n_gethostname_localhost;
+ prev_n_get_interface_address6 = n_get_interface_address6;
+
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
- &method_used,&hostname_out);
+ tt_int_op(n_get_interface_address6, OP_EQ, ++prev_n_get_interface_address6);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_INTERFACE, NULL);
+ CLEANUP_FOUND_ADDRESS;
+
+ /*
+ * Case 15: Address is a local address (internal) but we unset
+ * PublishServerDescriptor_ so we are allowed to hold it.
+ */
+ options->PublishServerDescriptor_ = NO_DIRINFO;
+ if (p->family == AF_INET) {
+ options->AssumeReachable = 1;
+ }
+ config_line_append(&options->Address, "Address", p->internal_ip);
- tt_want(n_gethostname_localhost == prev_n_gethostname_localhost + 1);
- tt_int_op(retval, OP_EQ, -1);
+ tor_addr_parse(&test_addr, p->internal_ip);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(get_interface_address6);
UNMOCK(tor_gethostname);
+ UNMOCK(tor_addr_lookup);
done:
- tor_free(options->Address);
- tor_free(options->DirAuthorities);
or_options_free(options);
- tor_free(hostname_out);
UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
- UNMOCK(get_interface_address);
+ UNMOCK(tor_addr_lookup);
UNMOCK(get_interface_address6);
- UNMOCK(tor_gethostname);
}
static void
@@ -1754,6 +2042,18 @@ add_default_fallback_dir_servers_known_default(void)
n_add_default_fallback_dir_servers_known_default++;
}
+/* Helper for test_config_adding_dir_servers(), which should be
+ * refactored: clear the fields in the options which the options object
+ * does not really own. */
+static void
+ads_clear_helper(or_options_t *options)
+{
+ options->DirAuthorities = NULL;
+ options->AlternateBridgeAuthority = NULL;
+ options->AlternateDirAuthority = NULL;
+ options->FallbackDir = NULL;
+}
+
/* Test all the different combinations of adding dir servers */
static void
test_config_adding_dir_servers(void *arg)
@@ -1761,7 +2061,7 @@ test_config_adding_dir_servers(void *arg)
(void)arg;
/* allocate options */
- or_options_t *options = tor_malloc_zero(sizeof(or_options_t));
+ or_options_t *options = options_new();
/* Allocate and populate configuration lines:
*
@@ -1884,7 +2184,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -1966,7 +2268,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2003,7 +2307,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 1);
@@ -2015,7 +2319,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -2027,7 +2331,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2046,7 +2350,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 1);
@@ -2058,7 +2362,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -2070,7 +2374,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2082,7 +2386,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 1);
@@ -2094,7 +2398,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -2107,7 +2411,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2144,7 +2450,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 1);
@@ -2156,7 +2462,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -2168,7 +2474,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2187,7 +2493,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 1);
@@ -2199,7 +2505,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -2211,7 +2517,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2223,7 +2529,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 0);
@@ -2235,7 +2541,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -2248,7 +2554,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2285,7 +2593,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2297,7 +2605,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2309,7 +2617,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -2328,7 +2636,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2340,7 +2648,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2352,7 +2660,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -2364,7 +2672,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 1);
@@ -2376,7 +2684,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -2390,7 +2698,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2427,7 +2737,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2439,7 +2749,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2451,7 +2761,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -2470,7 +2780,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2482,7 +2792,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2494,7 +2804,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -2506,7 +2816,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 0);
@@ -2518,7 +2828,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -2542,7 +2852,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2579,7 +2891,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2591,7 +2903,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2603,7 +2915,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2629,7 +2941,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2641,7 +2953,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2653,7 +2965,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2665,7 +2977,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 1);
@@ -2677,7 +2989,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -2696,7 +3008,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2733,7 +3047,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2745,7 +3059,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2757,7 +3071,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2783,7 +3097,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2795,7 +3109,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2807,7 +3121,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2819,7 +3133,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 0);
@@ -2831,7 +3145,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 1);
@@ -2859,7 +3173,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -2897,7 +3213,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2909,7 +3225,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -2921,7 +3237,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -2948,7 +3264,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2960,7 +3276,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -2972,7 +3288,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -2984,7 +3300,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 1);
@@ -2996,7 +3312,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -3016,7 +3332,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -3055,7 +3373,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3067,7 +3385,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3079,7 +3397,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -3106,7 +3424,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3118,7 +3436,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3130,7 +3448,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -3142,7 +3460,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 0);
@@ -3154,7 +3472,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -3182,7 +3500,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -3220,7 +3540,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3232,7 +3552,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3244,7 +3564,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -3271,7 +3591,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3283,7 +3603,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3295,7 +3615,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -3307,7 +3627,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 1);
@@ -3319,7 +3639,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -3345,7 +3665,9 @@ test_config_adding_dir_servers(void *arg)
n_add_default_fallback_dir_servers_known_default = 0;
/* clear options*/
- memset(options, 0, sizeof(or_options_t));
+ ads_clear_helper(options);
+ or_options_free(options);
+ options = options_new();
/* clear any previous dir servers:
consider_adding_dir_servers() should do this anyway */
@@ -3383,7 +3705,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3395,7 +3717,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3407,7 +3729,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -3434,7 +3756,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3446,7 +3768,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3458,7 +3780,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -3470,7 +3792,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 0);
@@ -3482,7 +3804,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 1);
@@ -3514,10 +3836,7 @@ test_config_adding_dir_servers(void *arg)
tor_free(test_fallback_directory->value);
tor_free(test_fallback_directory);
- options->DirAuthorities = NULL;
- options->AlternateBridgeAuthority = NULL;
- options->AlternateDirAuthority = NULL;
- options->FallbackDir = NULL;
+ ads_clear_helper(options);
or_options_free(options);
UNMOCK(add_default_fallback_dir_servers);
@@ -3532,7 +3851,7 @@ test_config_default_dir_servers(void *arg)
int fallback_count = 0;
/* new set of options should stop fallback parsing */
- opts = tor_malloc_zero(sizeof(or_options_t));
+ opts = options_new();
opts->UseDefaultFallbackDirs = 0;
/* set old_options to NULL to force dir update */
consider_adding_dir_servers(opts, NULL);
@@ -3546,7 +3865,7 @@ test_config_default_dir_servers(void *arg)
/* if we disable the default fallbacks, there must not be any extra */
tt_assert(fallback_count == trusted_count);
- opts = tor_malloc_zero(sizeof(or_options_t));
+ opts = options_new();
opts->UseDefaultFallbackDirs = 1;
consider_adding_dir_servers(opts, opts);
trusted_count = smartlist_len(router_get_trusted_dir_servers());
@@ -3564,16 +3883,17 @@ test_config_default_dir_servers(void *arg)
or_options_free(opts);
}
-static int mock_router_pick_published_address_result = 0;
+static bool mock_relay_find_addr_to_publish_result = true;
-static int
-mock_router_pick_published_address(const or_options_t *options,
- uint32_t *addr, int cache_only)
+static bool
+mock_relay_find_addr_to_publish(const or_options_t *options, int family,
+ int flags, tor_addr_t *addr_out)
{
- (void)options;
- (void)addr;
- (void)cache_only;
- return mock_router_pick_published_address_result;
+ (void) options;
+ (void) family;
+ (void) flags;
+ (void) addr_out;
+ return mock_relay_find_addr_to_publish_result;
}
static int mock_router_my_exit_policy_is_reject_star_result = 0;
@@ -3606,85 +3926,70 @@ test_config_directory_fetch(void *arg)
(void)arg;
/* Test Setup */
- or_options_t *options = tor_malloc_zero(sizeof(or_options_t));
+ or_options_t *options = options_new();
routerinfo_t routerinfo;
memset(&routerinfo, 0, sizeof(routerinfo));
- mock_router_pick_published_address_result = -1;
+ mock_relay_find_addr_to_publish_result = false;
mock_router_my_exit_policy_is_reject_star_result = 1;
mock_advertised_server_mode_result = 0;
mock_router_get_my_routerinfo_result = NULL;
- MOCK(router_pick_published_address, mock_router_pick_published_address);
+ MOCK(relay_find_addr_to_publish, mock_relay_find_addr_to_publish);
MOCK(router_my_exit_policy_is_reject_star,
mock_router_my_exit_policy_is_reject_star);
MOCK(advertised_server_mode, mock_advertised_server_mode);
MOCK(router_get_my_routerinfo, mock_router_get_my_routerinfo);
+ or_options_free(options);
+ options = options_new();
/* Clients can use multiple directory mirrors for bootstrap */
- memset(options, 0, sizeof(or_options_t));
options->ClientOnly = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 1);
/* Bridge Clients can use multiple directory mirrors for bootstrap */
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->UseBridges = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 1);
/* Bridge Relays (Bridges) must act like clients, and use multiple
* directory mirrors for bootstrap */
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->BridgeRelay = 1;
options->ORPort_set = 1;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 0);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 1);
/* Clients set to FetchDirInfoEarly must fetch it from the authorities,
* but can use multiple authorities for bootstrap */
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->FetchDirInfoEarly = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 1);
- /* OR servers only fetch the consensus from the authorities when they don't
- * know their own address, but never use multiple directories for bootstrap
- */
- memset(options, 0, sizeof(or_options_t));
- options->ORPort_set = 1;
-
- mock_router_pick_published_address_result = -1;
- tt_assert(server_mode(options) == 1);
- tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
- tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
- OP_EQ, 0);
-
- mock_router_pick_published_address_result = 0;
- tt_assert(server_mode(options) == 1);
- tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
- tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
- OP_EQ, 0);
-
/* Exit OR servers only fetch the consensus from the authorities when they
* refuse unknown exits, but never use multiple directories for bootstrap
*/
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->ORPort_set = 1;
options->ExitRelay = 1;
- mock_router_pick_published_address_result = 0;
+ mock_relay_find_addr_to_publish_result = true;
mock_router_my_exit_policy_is_reject_star_result = 0;
mock_advertised_server_mode_result = 1;
mock_router_get_my_routerinfo_result = &routerinfo;
@@ -3694,15 +3999,15 @@ test_config_directory_fetch(void *arg)
options->RefuseUnknownExits = 1;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
options->RefuseUnknownExits = 0;
- mock_router_pick_published_address_result = 0;
+ mock_relay_find_addr_to_publish_result = true;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
@@ -3711,28 +4016,29 @@ test_config_directory_fetch(void *arg)
* advertising their dirport, and never use multiple directories for
* bootstrap. This only applies if they are also OR servers.
* (We don't care much about the behaviour of non-OR directory servers.) */
- memset(options, 0, sizeof(or_options_t));
+ or_options_free(options);
+ options = options_new();
options->DirPort_set = 1;
options->ORPort_set = 1;
options->DirCache = 1;
- mock_router_pick_published_address_result = 0;
+ mock_relay_find_addr_to_publish_result = true;
mock_router_my_exit_policy_is_reject_star_result = 1;
mock_advertised_server_mode_result = 1;
- routerinfo.dir_port = 1;
+ routerinfo.ipv4_dirport = 1;
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
mock_advertised_server_mode_result = 0;
- routerinfo.dir_port = 1;
+ routerinfo.ipv4_dirport = 1;
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
@@ -3740,33 +4046,33 @@ test_config_directory_fetch(void *arg)
mock_router_get_my_routerinfo_result = NULL;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
mock_advertised_server_mode_result = 1;
- routerinfo.dir_port = 0;
+ routerinfo.ipv4_dirport = 0;
routerinfo.supports_tunnelled_dir_requests = 0;
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
mock_advertised_server_mode_result = 1;
- routerinfo.dir_port = 1;
+ routerinfo.ipv4_dirport = 1;
routerinfo.supports_tunnelled_dir_requests = 1;
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
done:
- tor_free(options);
- UNMOCK(router_pick_published_address);
+ or_options_free(options);
+ UNMOCK(relay_find_addr_to_publish);
UNMOCK(router_get_my_routerinfo);
UNMOCK(advertised_server_mode);
UNMOCK(router_my_exit_policy_is_reject_star);
@@ -3776,7 +4082,9 @@ static void
test_config_default_fallback_dirs(void *arg)
{
const char *fallback[] = {
+#ifndef COCCI
#include "app/config/fallback_dirs.inc"
+#endif
NULL
};
@@ -3958,40 +4266,40 @@ test_config_parse_port_config__ports__no_ports_given(void *data)
slout = smartlist_new();
// Test no defaultport, no defaultaddress and no out
- ret = parse_port_config(NULL, NULL, "DNS", 0, NULL, 0, 0);
+ ret = port_parse_config(NULL, NULL, "DNS", 0, NULL, 0, 0);
tt_int_op(ret, OP_EQ, 0);
// Test with defaultport, no defaultaddress and no out
- ret = parse_port_config(NULL, NULL, "DNS", 0, NULL, 42, 0);
+ ret = port_parse_config(NULL, NULL, "DNS", 0, NULL, 42, 0);
tt_int_op(ret, OP_EQ, 0);
// Test no defaultport, with defaultaddress and no out
- ret = parse_port_config(NULL, NULL, "DNS", 0, "127.0.0.2", 0, 0);
+ ret = port_parse_config(NULL, NULL, "DNS", 0, "127.0.0.2", 0, 0);
tt_int_op(ret, OP_EQ, 0);
// Test with defaultport, with defaultaddress and no out
- ret = parse_port_config(NULL, NULL, "DNS", 0, "127.0.0.2", 42, 0);
+ ret = port_parse_config(NULL, NULL, "DNS", 0, "127.0.0.2", 42, 0);
tt_int_op(ret, OP_EQ, 0);
// Test no defaultport, no defaultaddress and with out
- ret = parse_port_config(slout, NULL, "DNS", 0, NULL, 0, 0);
+ ret = port_parse_config(slout, NULL, "DNS", 0, NULL, 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
// Test with defaultport, no defaultaddress and with out
- ret = parse_port_config(slout, NULL, "DNS", 0, NULL, 42, 0);
+ ret = port_parse_config(slout, NULL, "DNS", 0, NULL, 42, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
// Test no defaultport, with defaultaddress and with out
- ret = parse_port_config(slout, NULL, "DNS", 0, "127.0.0.2", 0, 0);
+ ret = port_parse_config(slout, NULL, "DNS", 0, "127.0.0.2", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
// Test with defaultport, with defaultaddress and out, adds a new port cfg
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, NULL, "DNS", 0, "127.0.0.2", 42, 0);
+ ret = port_parse_config(slout, NULL, "DNS", 0, "127.0.0.2", 42, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
@@ -4002,7 +4310,7 @@ test_config_parse_port_config__ports__no_ports_given(void *data)
// for a unix address
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, NULL, "DNS", 0, "/foo/bar/unixdomain",
+ ret = port_parse_config(slout, NULL, "DNS", 0, "/foo/bar/unixdomain",
42, CL_PORT_IS_UNIXSOCKET);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4029,30 +4337,32 @@ test_config_parse_port_config__ports__ports_given(void *data)
slout = smartlist_new();
+ mock_hostname_resolver();
+
// Test error when encounters an invalid Port specification
config_port_invalid = mock_config_line("DNSPort", "");
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0, NULL,
0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test error when encounters an empty unix domain specification
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "unix:");
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0, NULL,
0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test error when encounters a unix domain specification but the listener
// doesn't support domain sockets
config_port_valid = mock_config_line("DNSPort", "unix:/tmp/foo/bar");
- ret = parse_port_config(NULL, config_port_valid, "DNS",
+ ret = port_parse_config(NULL, config_port_valid, "DNS",
CONN_TYPE_AP_DNS_LISTENER, NULL, 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test valid unix domain
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0, 0);
#ifdef _WIN32
tt_int_op(ret, OP_EQ, -1);
@@ -4063,7 +4373,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(port_cfg->port, OP_EQ, 0);
tt_int_op(port_cfg->is_unix_addr, OP_EQ, 1);
tt_str_op(port_cfg->unix_addr, OP_EQ, "/tmp/foo/bar");
- /* Test entry port defaults as initialised in parse_port_config */
+ /* 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.onion_traffic, OP_EQ, 1);
@@ -4077,7 +4387,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
"unix:/tmp/foo/bar NoIPv4Traffic "
"NoIPv6Traffic "
"NoOnionTraffic");
- ret = parse_port_config(NULL, config_port_invalid, "SOCKS",
+ ret = port_parse_config(NULL, config_port_invalid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4086,7 +4396,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort",
"127.0.0.1:80 NoDNSRequest");
- ret = parse_port_config(NULL, config_port_invalid, "DNS",
+ ret = port_parse_config(NULL, config_port_invalid, "DNS",
CONN_TYPE_AP_DNS_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4099,7 +4409,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_valid = mock_config_line("DNSPort", "127.0.0.1:80 "
"NoIPv6Traffic "
"NoIPv4Traffic NoOnionTraffic");
- ret = parse_port_config(slout, config_port_valid, "DNS",
+ ret = port_parse_config(slout, config_port_valid, "DNS",
CONN_TYPE_AP_DNS_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, 0);
@@ -4115,7 +4425,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_invalid = mock_config_line("SOCKSPort",
"NoIPv6Traffic "
"unix:/tmp/foo/bar NoIPv4Traffic");
- ret = parse_port_config(NULL, config_port_invalid, "SOCKS",
+ ret = port_parse_config(NULL, config_port_invalid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4128,7 +4438,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4150,7 +4460,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_valid = mock_config_line("SOCKSPort", "unix:\"/tmp/foo/ bar\" "
"NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4172,7 +4482,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_valid = mock_config_line("SOCKSPort", "unix:\"/tmp/foo/ bar "
"NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4184,7 +4494,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_valid = mock_config_line("SOCKSPort", "unix:\"\" "
"NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4195,7 +4505,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"OnionTrafficOnly");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4216,7 +4526,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"NoIPv4Traffic IPv6Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4235,7 +4545,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"IPv4Traffic IPv6Traffic");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4251,28 +4561,28 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test failure if we specify world writable for an IP Port
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "42 WorldWritable");
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test failure if we specify group writable for an IP Port
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "42 GroupWritable");
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test failure if we specify group writable for an IP Port
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "42 RelaxDirModeCheck");
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test success with only a port (this will fail without a default address)
config_free_lines(config_port_valid); config_port_valid = NULL;
config_port_valid = mock_config_line("DNSPort", "42");
- ret = parse_port_config(NULL, config_port_valid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -4281,7 +4591,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateDestPort");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4294,7 +4604,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoIsolateDestPorts");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4307,7 +4617,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateDestAddr");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4320,7 +4630,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateSOCKSAuth");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4333,7 +4643,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateClientProtocol");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4346,7 +4656,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateClientAddr");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4357,7 +4667,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test success with ignored unknown options
config_free_lines(config_port_valid); config_port_valid = NULL;
config_port_valid = mock_config_line("DNSPort", "42 ThisOptionDoesntExist");
- ret = parse_port_config(NULL, config_port_valid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -4366,7 +4676,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoIsolateSOCKSAuth");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4379,7 +4689,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort",
"42 IPv6Traffic PreferIPv6");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, "127.0.0.42", 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, 0);
@@ -4392,7 +4702,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 CacheIPv4DNS");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4405,7 +4715,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 CacheIPv6DNS");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4418,7 +4728,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoCacheIPv4DNS");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4431,7 +4741,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 CacheDNS");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4444,7 +4754,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 UseIPv4Cache");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4457,7 +4767,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 UseIPv6Cache");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4470,7 +4780,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 UseDNSCache");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4483,7 +4793,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoPreferIPv6Automap");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4495,7 +4805,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 PreferSOCKSNoAuth");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4510,14 +4820,14 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_invalid = mock_config_line("DNSPort", "0");
config_port_valid = mock_config_line("DNSPort", "42");
config_port_invalid->next = config_port_valid;
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test success with warn non-local control
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, "Control",
+ ret = port_parse_config(slout, config_port_valid, "Control",
CONN_TYPE_CONTROL_LISTENER, "127.0.0.42", 0,
CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
@@ -4525,7 +4835,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test success with warn non-local listener
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, "ExtOR",
+ ret = port_parse_config(slout, config_port_valid, "ExtOR",
CONN_TYPE_EXT_OR_LISTENER, "127.0.0.42", 0,
CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
@@ -4533,12 +4843,12 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test success with warn non-local other
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
// Test success with warn non-local other without out
- ret = parse_port_config(NULL, config_port_valid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_valid, "DNS", 0,
"127.0.0.42", 0, CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
@@ -4549,7 +4859,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IPv4Traffic "
"IPv6Traffic");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.44", 0,
CL_PORT_TAKES_HOSTNAMES |
CL_PORT_NO_STREAM_OPTIONS);
@@ -4564,7 +4874,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=invalid");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4574,7 +4884,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4584,7 +4894,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123 "
"SessionGroup=321");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.44", 0, 0);
tt_int_op(ret, OP_EQ, -1);
@@ -4593,29 +4903,29 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 SessionGroup=1111122");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.44", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->entry_cfg.session_group, OP_EQ, 1111122);
- // Test success with a zero unix domain socket, and doesnt add it to out
+ // Test success with a zero unix domain socket, and doesn't add it to out
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "0");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.45", 0, CL_PORT_IS_UNIXSOCKET);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
- // Test success with a one unix domain socket, and doesnt add it to out
+ // Test success with a one unix domain socket, and doesn't add it to out
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "something");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.45", 0, CL_PORT_IS_UNIXSOCKET);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4628,48 +4938,48 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "auto");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->port, OP_EQ, CFG_AUTO_PORT);
tor_addr_parse(&addr, "127.0.0.46");
- tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ tt_assert(tor_addr_eq(&port_cfg->addr, &addr));
// Test success with a port of auto in mixed case
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "AuTo");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->port, OP_EQ, CFG_AUTO_PORT);
tor_addr_parse(&addr, "127.0.0.46");
- tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ tt_assert(tor_addr_eq(&port_cfg->addr, &addr));
// Test success with parsing both an address and an auto port
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.122:auto");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->port, OP_EQ, CFG_AUTO_PORT);
tor_addr_parse(&addr, "127.0.0.122");
- tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ tt_assert(tor_addr_eq(&port_cfg->addr, &addr));
// Test failure when asked to parse an invalid address followed by auto
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "invalidstuff!!:auto");
MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
- ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.46", 0, 0);
UNMOCK(tor_addr_lookup);
tt_int_op(ret, OP_EQ, -1);
@@ -4679,21 +4989,21 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.123:656");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->port, OP_EQ, 656);
tor_addr_parse(&addr, "127.0.0.123");
- tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ tt_assert(tor_addr_eq(&port_cfg->addr, &addr));
// Test failure if we can't parse anything at all
config_free_lines(config_port_invalid); config_port_invalid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "something wrong");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, -1);
@@ -4702,7 +5012,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "127.0.1.0:123:auto");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, -1);
@@ -4712,7 +5022,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/somewhere");
- ret = parse_port_config(slout, config_port_valid, "SOCKS",
+ ret = port_parse_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, "127.0.0.46", 0,
CL_PORT_DFLT_GROUP_WRITABLE);
#ifdef _WIN32
@@ -4725,6 +5035,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
#endif /* defined(_WIN32) */
done:
+ unmock_hostname_resolver();
if (slout)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_free(slout);
@@ -4747,7 +5058,7 @@ test_config_parse_port_config__ports__server_options(void *data)
config_free_lines(config_port_valid); config_port_valid = NULL;
config_port_valid = mock_config_line("DNSPort",
"127.0.0.124:656 NoAdvertise");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4760,7 +5071,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 NoListen");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4774,7 +5085,7 @@ test_config_parse_port_config__ports__server_options(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "127.0.0.124:656 NoListen "
"NoAdvertise");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4783,7 +5094,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 IPv4Only");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4796,7 +5107,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "[::1]:656 IPv6Only");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4810,7 +5121,7 @@ test_config_parse_port_config__ports__server_options(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "127.0.0.124:656 IPv6Only "
"IPv4Only");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4819,7 +5130,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 unknown");
- ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
+ ret = port_parse_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4830,7 +5141,7 @@ test_config_parse_port_config__ports__server_options(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort",
"127.0.0.124:656 IPv6Only");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4839,7 +5150,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "[::1]:656 IPv4Only");
- ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
+ ret = port_parse_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4848,10 +5159,48 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("ORPort", "unix:\"\"");
- ret = parse_port_config(slout, config_port_invalid, "ORPort", 0, NULL,
+ ret = port_parse_config(slout, config_port_invalid, "ORPort", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
+ /* Default address is IPv4 but pass IPv6Only flag. Should be ignored. */
+ config_free_lines(config_port_invalid); config_port_invalid = NULL;
+ SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+ smartlist_clear(slout);
+ config_port_invalid = mock_config_line("ORPort", "9050 IPv6Only");
+ ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+ "127.0.0.1", 0, CL_PORT_SERVER_OPTIONS);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Default address is IPv6 but pass IPv4Only flag. Should be ignored. */
+ config_free_lines(config_port_invalid); config_port_invalid = NULL;
+ SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+ smartlist_clear(slout);
+ config_port_invalid = mock_config_line("ORPort", "9050 IPv4Only");
+ ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+ "[::]", 0, CL_PORT_SERVER_OPTIONS);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Explicit address is IPv6 but pass IPv4Only flag. Should error. */
+ config_free_lines(config_port_invalid); config_port_invalid = NULL;
+ SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+ smartlist_clear(slout);
+ config_port_invalid = mock_config_line("ORPort",
+ "[4242::4242]:9050 IPv4Only");
+ ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+ "[::]", 0, CL_PORT_SERVER_OPTIONS);
+ tt_int_op(ret, OP_EQ, -1);
+
+ /* Explicit address is IPv4 but pass IPv6Only flag. Should error. */
+ config_free_lines(config_port_invalid); config_port_invalid = NULL;
+ SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+ smartlist_clear(slout);
+ config_port_invalid = mock_config_line("ORPort",
+ "1.2.3.4:9050 IPv6Only");
+ ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+ "127.0.0.1", 0, CL_PORT_SERVER_OPTIONS);
+ tt_int_op(ret, OP_EQ, -1);
+
done:
if (slout)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
@@ -4871,17 +5220,17 @@ test_config_get_first_advertised(void *data)
const tor_addr_t *addr;
// no ports are configured? We get NULL.
- port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
AF_INET);
tt_int_op(port, OP_EQ, 0);
- addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER,
AF_INET);
tt_ptr_op(addr, OP_EQ, NULL);
- port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
AF_INET6);
tt_int_op(port, OP_EQ, 0);
- addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER,
AF_INET6);
tt_ptr_op(addr, OP_EQ, NULL);
@@ -4895,27 +5244,27 @@ test_config_get_first_advertised(void *data)
tt_assert(r == 0);
// UNSPEC gets us nothing.
- port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
AF_UNSPEC);
tt_int_op(port, OP_EQ, 0);
- addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER,
AF_UNSPEC);
tt_ptr_op(addr, OP_EQ, NULL);
// Try AF_INET.
- port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
AF_INET);
tt_int_op(port, OP_EQ, 9911);
- addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER,
AF_INET);
tt_ptr_op(addr, OP_NE, NULL);
tt_str_op(fmt_addrport(addr,port), OP_EQ, "5.6.7.8:9911");
// Try AF_INET6
- port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
AF_INET6);
tt_int_op(port, OP_EQ, 8080);
- addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER,
AF_INET6);
tt_ptr_op(addr, OP_NE, NULL);
tt_str_op(fmt_addrport(addr,port), OP_EQ, "[1234::5678]:8080");
@@ -5128,7 +5477,7 @@ test_config_include_no_permission(void *data)
chmod(dir, 0700);
tor_free(dir);
}
-#endif
+#endif /* !defined(_WIN32) */
static void
test_config_include_recursion_before_after(void *data)
@@ -5538,6 +5887,7 @@ test_config_include_flag_both_without(void *data)
done:
tor_free(errmsg);
+ config_free_all();
}
static void
@@ -5578,6 +5928,7 @@ test_config_include_flag_torrc_only(void *data)
tor_free(errmsg);
tor_free(path);
tor_free(dir);
+ config_free_all();
}
static void
@@ -5618,6 +5969,287 @@ test_config_include_flag_defaults_only(void *data)
tor_free(errmsg);
tor_free(path);
tor_free(dir);
+ config_free_all();
+}
+
+static void
+test_config_include_wildcards(void *data)
+{
+ (void)data;
+
+ char *temp = NULL, *folder = NULL;
+ config_line_t *result = NULL;
+ char *dir = tor_strdup(get_fname("test_include_wildcards"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", dir, "01_one.conf");
+ tt_int_op(write_str_to_file(temp, "Test 1\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", dir, "02_two.conf");
+ tt_int_op(write_str_to_file(temp, "Test 2\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", dir, "aa_three.conf");
+ tt_int_op(write_str_to_file(temp, "Test 3\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", dir, "foo");
+ tt_int_op(write_str_to_file(temp, "Test 6\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&folder, "%s"PATH_SEPARATOR"%s", dir, "folder");
+
+#ifdef _WIN32
+ tt_int_op(mkdir(folder), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(folder, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", folder, "04_four.conf");
+ tt_int_op(write_str_to_file(temp, "Test 4\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", folder, "05_five.conf");
+ tt_int_op(write_str_to_file(temp, "Test 5\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ char torrc_contents[1000];
+ int include_used;
+
+ // test pattern that matches no file
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"not-exist*\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_EQ, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+ config_free_lines(result);
+
+#ifndef _WIN32
+ // test wildcard escaping
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"\\*\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, -1);
+ tt_ptr_op(result, OP_EQ, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+ config_free_lines(result);
+#endif
+
+ // test pattern *.conf
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*.conf\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ int len = 0;
+ config_line_t *next;
+ char expected[10];
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 3);
+ config_free_lines(result);
+
+ // test pattern that matches folder and files
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 6);
+ config_free_lines(result);
+
+ // test pattern ending in PATH_SEPARATOR, test linux path separator
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s/f*/\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1 + 3);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 2);
+ config_free_lines(result);
+
+ // test pattern with wildcards in folder and file
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*"PATH_SEPARATOR"*.conf\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1 + 3);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 2);
+ config_free_lines(result);
+
+ done:
+ config_free_lines(result);
+ tor_free(folder);
+ tor_free(temp);
+ tor_free(dir);
+}
+
+static void
+test_config_include_hidden(void *data)
+{
+ (void)data;
+
+ char *temp = NULL, *folder = NULL;
+ config_line_t *result = NULL;
+ char *dir = tor_strdup(get_fname("test_include_hidden"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&folder, "%s"PATH_SEPARATOR"%s", dir, ".dotdir");
+
+#ifdef _WIN32
+ tt_int_op(mkdir(folder), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(folder, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", folder, ".dotfile");
+ tt_int_op(write_str_to_file(temp, "Test 1\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", folder, "file");
+ tt_int_op(write_str_to_file(temp, "Test 2\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ char torrc_contents[1000];
+ int include_used;
+ int len = 0;
+ config_line_t *next;
+ char expected[10];
+
+ // test wildcards do not expand to dot folders (except for windows)
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_int_op(include_used, OP_EQ, 1);
+#ifdef _WIN32 // wildcard expansion includes dot files on Windows
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 2);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 1);
+#else
+ tt_ptr_op(result, OP_EQ, NULL);
+#endif
+ config_free_lines(result);
+
+ // test wildcards match hidden folders when explicitly in the pattern
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR".*\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 2);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 1);
+ config_free_lines(result);
+
+ // test hidden dir when explicitly included
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR".dotdir\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 2);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 1);
+ config_free_lines(result);
+
+ // test hidden file when explicitly included
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR".dotdir"PATH_SEPARATOR".dotfile\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 1);
+ config_free_lines(result);
+
+ done:
+ config_free_lines(result);
+ tor_free(folder);
+ tor_free(temp);
+ tor_free(dir);
}
static void
@@ -5662,7 +6294,6 @@ test_config_check_bridge_distribution_setting_not_a_bridge(void *arg)
{
or_options_t* options = get_options_mutable();
or_options_t* old_options = options;
- or_options_t* default_options = options;
char* message = NULL;
int ret;
@@ -5671,7 +6302,7 @@ test_config_check_bridge_distribution_setting_not_a_bridge(void *arg)
options->BridgeRelay = 0;
options->BridgeDistribution = (char*)("https");
- ret = options_validate(old_options, options, default_options, 0, &message);
+ ret = options_validate(old_options, options, &message);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(message, OP_EQ, "You set BridgeDistribution, but you "
@@ -5750,7 +6381,7 @@ test_config_include_opened_file_list(void *data)
smartlist_t *opened_files = smartlist_new();
char *torrcd = NULL;
char *subfolder = NULL;
- char *path = NULL;
+ char *in_subfolder = NULL;
char *empty = NULL;
char *file = NULL;
char *dot = NULL;
@@ -5779,9 +6410,9 @@ test_config_include_opened_file_list(void *data)
tt_int_op(mkdir(subfolder, 0700), OP_EQ, 0);
#endif
- tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", subfolder,
+ tor_asprintf(&in_subfolder, "%s"PATH_SEPARATOR"%s", subfolder,
"01_file_in_subfolder");
- tt_int_op(write_str_to_file(path, "Test 1\n", 0), OP_EQ, 0);
+ tt_int_op(write_str_to_file(in_subfolder, "Test 1\n", 0), OP_EQ, 0);
tor_asprintf(&empty, "%s"PATH_SEPARATOR"%s", torrcd, "empty");
tt_int_op(write_str_to_file(empty, "", 0), OP_EQ, 0);
@@ -5812,13 +6443,69 @@ test_config_include_opened_file_list(void *data)
// dot files are not opened as we ignore them when we get their name from
// their parent folder
+ // test with wildcards
+ SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f));
+ smartlist_clear(opened_files);
+ config_free_lines(result);
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*\n",
+ torrcd);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ opened_files), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+#ifdef _WIN32
+ tt_int_op(smartlist_len(opened_files), OP_EQ, 6);
+#else
+ tt_int_op(smartlist_len(opened_files), OP_EQ, 5);
+#endif
+ tt_int_op(smartlist_contains_string(opened_files, torrcd), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, subfolder), OP_EQ, 1);
+ // * will match the subfolder inside torrc.d, so it will be included
+ tt_int_op(smartlist_contains_string(opened_files, in_subfolder), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, empty), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, file), OP_EQ, 1);
+#ifdef _WIN32
+ // * matches the dot file on Windows
+ tt_int_op(smartlist_contains_string(opened_files, dot), OP_EQ, 1);
+#endif
+
+ // test with wildcards in folder and file
+ SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f));
+ smartlist_clear(opened_files);
+ config_free_lines(result);
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*"PATH_SEPARATOR"*\n",
+ torrcd);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ opened_files), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+#ifdef _WIN32
+ tt_int_op(smartlist_len(opened_files), OP_EQ, 6);
+#else
+ tt_int_op(smartlist_len(opened_files), OP_EQ, 5);
+#endif
+ tt_int_op(smartlist_contains_string(opened_files, torrcd), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, subfolder), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, in_subfolder), OP_EQ, 1);
+ // stat is called on the following files, so they count as opened
+ tt_int_op(smartlist_contains_string(opened_files, empty), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, file), OP_EQ, 1);
+#ifdef _WIN32
+ // * matches the dot file on Windows
+ tt_int_op(smartlist_contains_string(opened_files, dot), OP_EQ, 1);
+#endif
+
done:
SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f));
smartlist_free(opened_files);
config_free_lines(result);
tor_free(torrcd);
tor_free(subfolder);
- tor_free(path);
+ tor_free(in_subfolder);
tor_free(empty);
tor_free(file);
tor_free(dot);
@@ -5843,7 +6530,7 @@ test_config_compute_max_mem_in_queues(void *data)
#else
/* We are on a 32-bit system. */
tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ, GIGABYTE(1));
-#endif
+#endif /* SIZEOF_VOID_P >= 8 */
/* We are able to detect the amount of RAM on the system. */
total_system_memory_return = 0;
@@ -5884,7 +6571,7 @@ test_config_compute_max_mem_in_queues(void *data)
/* We will at maximum get MAX_DEFAULT_MEMORY_QUEUE_SIZE here. */
tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ,
MAX_DEFAULT_MEMORY_QUEUE_SIZE);
-#endif
+#endif /* SIZEOF_SIZE_T > 4 */
done:
UNMOCK(get_total_system_memory);
@@ -5928,6 +6615,7 @@ test_config_extended_fmt(void *arg)
tt_str_op(lp->value, OP_EQ, "is back here");
tt_int_op(lp->command, OP_EQ, CONFIG_LINE_NORMAL);
lp = lp->next;
+ tt_assert(!lp);
config_free_lines(lines);
/* Try with the "extended" flag enabled. */
@@ -5954,14 +6642,361 @@ test_config_extended_fmt(void *arg)
tt_str_op(lp->value, OP_EQ, "");
tt_int_op(lp->command, OP_EQ, CONFIG_LINE_CLEAR);
lp = lp->next;
+ tt_assert(!lp);
+
+ done:
+ config_free_lines(lines);
+}
+
+static void
+test_config_kvline_parse(void *arg)
+{
+ (void)arg;
+
+ config_line_t *lines = NULL;
+ char *enc = NULL;
+
+ lines = kvline_parse("A=B CD=EF", 0);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "A");
+ tt_str_op(lines->value, OP_EQ, "B");
+ tt_str_op(lines->next->key, OP_EQ, "CD");
+ tt_str_op(lines->next->value, OP_EQ, "EF");
+ enc = kvline_encode(lines, 0);
+ tt_str_op(enc, OP_EQ, "A=B CD=EF");
+ tor_free(enc);
+ enc = kvline_encode(lines, KV_QUOTED|KV_OMIT_KEYS);
+ tt_str_op(enc, OP_EQ, "A=B CD=EF");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB CDE=F", 0);
+ tt_assert(! lines);
+
+ lines = kvline_parse("AB CDE=F", KV_OMIT_KEYS);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "");
+ tt_str_op(lines->value, OP_EQ, "AB");
+ tt_str_op(lines->next->key, OP_EQ, "CDE");
+ tt_str_op(lines->next->value, OP_EQ, "F");
+ tt_assert(lines);
+ enc = kvline_encode(lines, 0);
+ tt_assert(!enc);
+ enc = kvline_encode(lines, KV_QUOTED|KV_OMIT_KEYS);
+ tt_str_op(enc, OP_EQ, "AB CDE=F");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB=C CDE=\"F G\"", 0);
+ tt_assert(!lines);
+
+ lines = kvline_parse("AB=C CDE=\"F G\" \"GHI\" ", KV_QUOTED|KV_OMIT_KEYS);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "C");
+ tt_str_op(lines->next->key, OP_EQ, "CDE");
+ tt_str_op(lines->next->value, OP_EQ, "F G");
+ tt_str_op(lines->next->next->key, OP_EQ, "");
+ tt_str_op(lines->next->next->value, OP_EQ, "GHI");
+ enc = kvline_encode(lines, 0);
+ tt_assert(!enc);
+ enc = kvline_encode(lines, KV_QUOTED|KV_OMIT_KEYS);
+ tt_str_op(enc, OP_EQ, "AB=C CDE=\"F G\" GHI");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = kvline_parse("A\"B=C CDE=\"F\" \"GHI\" ", KV_QUOTED|KV_OMIT_KEYS);
+ tt_assert(! lines);
+
+ lines = kvline_parse("AB=", KV_QUOTED);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "");
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB=", 0);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "");
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB=", KV_OMIT_VALS);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "");
+ config_free_lines(lines);
+
+ lines = kvline_parse(" AB ", KV_OMIT_VALS);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "");
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB", KV_OMIT_VALS);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "");
+ enc = kvline_encode(lines, KV_OMIT_VALS);
+ tt_str_op(enc, OP_EQ, "AB");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB=CD", KV_OMIT_VALS);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "CD");
+ enc = kvline_encode(lines, KV_OMIT_VALS);
+ tt_str_op(enc, OP_EQ, "AB=CD");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB=CD DE FGH=I", KV_OMIT_VALS);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "CD");
+ tt_str_op(lines->next->key, OP_EQ, "DE");
+ tt_str_op(lines->next->value, OP_EQ, "");
+ tt_str_op(lines->next->next->key, OP_EQ, "FGH");
+ tt_str_op(lines->next->next->value, OP_EQ, "I");
+ enc = kvline_encode(lines, KV_OMIT_VALS);
+ tt_str_op(enc, OP_EQ, "AB=CD DE FGH=I");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB=\"CD E\" DE FGH=\"I\"", KV_OMIT_VALS|KV_QUOTED);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "CD E");
+ tt_str_op(lines->next->key, OP_EQ, "DE");
+ tt_str_op(lines->next->value, OP_EQ, "");
+ tt_str_op(lines->next->next->key, OP_EQ, "FGH");
+ tt_str_op(lines->next->next->value, OP_EQ, "I");
+ enc = kvline_encode(lines, KV_OMIT_VALS|KV_QUOTED);
+ tt_str_op(enc, OP_EQ, "AB=\"CD E\" DE FGH=I");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB=CD \"EF=GH\"", KV_OMIT_KEYS|KV_QUOTED);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "CD");
+ tt_str_op(lines->next->key, OP_EQ, "");
+ tt_str_op(lines->next->value, OP_EQ, "EF=GH");
+ enc = kvline_encode(lines, KV_OMIT_KEYS);
+ tt_assert(!enc);
+ enc = kvline_encode(lines, KV_OMIT_KEYS|KV_QUOTED);
+ tt_assert(enc);
+ tt_str_op(enc, OP_EQ, "AB=CD \"EF=GH\"");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = tor_malloc_zero(sizeof(*lines));
+ lines->key = tor_strdup("A=B");
+ lines->value = tor_strdup("CD");
+ enc = kvline_encode(lines, 0);
+ tt_assert(!enc);
+ config_free_lines(lines);
+
+ config_line_append(&lines, "A", "B C");
+ enc = kvline_encode(lines, 0);
+ tt_assert(!enc);
+ enc = kvline_encode(lines, KV_RAW);
+ tt_assert(enc);
+ tt_str_op(enc, OP_EQ, "A=B C");
done:
config_free_lines(lines);
+ tor_free(enc);
}
+static void
+test_config_getinfo_config_names(void *arg)
+{
+ (void)arg;
+ char *answer = NULL;
+ const char *error = NULL;
+ int rv;
+
+ rv = getinfo_helper_config(NULL, "config/names", &answer, &error);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(error, OP_EQ, NULL);
+
+ // ContactInfo should be listed.
+ tt_assert(strstr(answer, "\nContactInfo String\n"));
+
+ // V1AuthoritativeDirectory should not be listed, since it is obsolete.
+ tt_assert(! strstr(answer, "V1AuthoritativeDirectory"));
+
+ // ___UsingTestNetworkDefaults should not be listed, since it is invisible.
+ tt_assert(! strstr(answer, "UsingTestNetworkDefaults"));
+
+ done:
+ tor_free(answer);
+}
+
+static void
+test_config_duplicate_orports(void *arg)
+{
+ (void)arg;
+
+ config_line_t *config_port = NULL;
+ smartlist_t *ports = smartlist_new();
+
+ // Pretend that the user has specified an implicit 0.0.0.0:9050, an implicit
+ // [::]:9050, and an explicit on [::1]:9050.
+ config_line_append(&config_port, "ORPort", "9050"); // two implicit entries.
+ config_line_append(&config_port, "ORPort", "[::1]:9050");
+
+ // Parse IPv4, then IPv6.
+ port_parse_config(ports, config_port, "OR", CONN_TYPE_OR_LISTENER, "0.0.0.0",
+ 0, CL_PORT_SERVER_OPTIONS);
+ port_parse_config(ports, config_port, "OR", CONN_TYPE_OR_LISTENER, "[::]",
+ 0, CL_PORT_SERVER_OPTIONS);
+
+ /* There should be 4 ports at this point that is:
+ * - 0.0.0.0:9050
+ * - [::]:9050
+ * - [::1]:9050
+ * - [::1]:9050
+ */
+ tt_int_op(smartlist_len(ports), OP_EQ, 4);
+
+ /* This will remove the [::] and the extra [::1]. */
+ remove_duplicate_orports(ports);
+
+ tt_int_op(smartlist_len(ports), OP_EQ, 2);
+ tt_str_op(describe_relay_port(smartlist_get(ports, 0)), OP_EQ,
+ "ORPort 9050");
+ tt_str_op(describe_relay_port(smartlist_get(ports, 1)), OP_EQ,
+ "ORPort [::1]:9050");
+
+ /* Reset. Test different ORPort value. */
+ SMARTLIST_FOREACH(ports, port_cfg_t *, p, port_cfg_free(p));
+ smartlist_free(ports);
+ config_free_lines(config_port);
+ config_port = NULL;
+ ports = smartlist_new();
+
+ /* Implicit port and then specific IPv6 addresses but more than one. */
+ config_line_append(&config_port, "ORPort", "9050"); // two implicit entries.
+ config_line_append(&config_port, "ORPort", "[4242::1]:9051");
+ config_line_append(&config_port, "ORPort", "[4242::2]:9051");
+
+ // Parse IPv4, then IPv6.
+ port_parse_config(ports, config_port, "OR", CONN_TYPE_OR_LISTENER, "0.0.0.0",
+ 0, CL_PORT_SERVER_OPTIONS);
+ port_parse_config(ports, config_port, "OR", CONN_TYPE_OR_LISTENER, "[::]",
+ 0, CL_PORT_SERVER_OPTIONS);
+
+ /* There should be 6 ports at this point that is:
+ * - 0.0.0.0:9050
+ * - [::]:9050
+ * - [4242::1]:9051
+ * - [4242::1]:9051
+ * - [4242::2]:9051
+ * - [4242::2]:9051
+ */
+ tt_int_op(smartlist_len(ports), OP_EQ, 6);
+
+ /* This will remove the [::] and the duplicates. */
+ remove_duplicate_orports(ports);
+
+ /* We have four address here, 1 IPv4 on 9050, IPv6 on 9050, IPv6 on 9051 and
+ * a different IPv6 on 9051. */
+ tt_int_op(smartlist_len(ports), OP_EQ, 4);
+ tt_str_op(describe_relay_port(smartlist_get(ports, 0)), OP_EQ,
+ "ORPort 9050");
+ tt_str_op(describe_relay_port(smartlist_get(ports, 1)), OP_EQ,
+ "ORPort [4242::1]:9051");
+ tt_str_op(describe_relay_port(smartlist_get(ports, 2)), OP_EQ,
+ "ORPort [4242::2]:9051");
+ tt_str_op(describe_relay_port(smartlist_get(ports, 3)), OP_EQ,
+ "ORPort 9050");
+
+ /* Reset. Test different ORPort value. */
+ SMARTLIST_FOREACH(ports, port_cfg_t *, p, port_cfg_free(p));
+ smartlist_free(ports);
+ config_free_lines(config_port);
+ config_port = NULL;
+ ports = smartlist_new();
+
+ /* Three different ports. */
+ config_line_append(&config_port, "ORPort", "9050"); // two implicit entries.
+ config_line_append(&config_port, "ORPort", "[4242::1]:9051");
+ config_line_append(&config_port, "ORPort", "[4242::2]:9052");
+
+ // Parse IPv4, then IPv6.
+ port_parse_config(ports, config_port, "OR", CONN_TYPE_OR_LISTENER, "0.0.0.0",
+ 0, CL_PORT_SERVER_OPTIONS);
+ port_parse_config(ports, config_port, "OR", CONN_TYPE_OR_LISTENER, "[::]",
+ 0, CL_PORT_SERVER_OPTIONS);
+
+ /* There should be 6 ports at this point that is:
+ * - 0.0.0.0:9050
+ * - [::]:9050
+ * - [4242::1]:9051
+ * - [4242::1]:9051
+ * - [4242::2]:9052
+ * - [4242::2]:9052
+ */
+ tt_int_op(smartlist_len(ports), OP_EQ, 6);
+
+ /* This will remove the [::] and the duplicates. */
+ remove_duplicate_orports(ports);
+
+ /* We have four address here, 1 IPv4 on 9050, IPv6 on 9050, IPv6 on 9051 and
+ * IPv6 on 9052. */
+ tt_int_op(smartlist_len(ports), OP_EQ, 4);
+ tt_str_op(describe_relay_port(smartlist_get(ports, 0)), OP_EQ,
+ "ORPort 9050");
+ tt_str_op(describe_relay_port(smartlist_get(ports, 1)), OP_EQ,
+ "ORPort [4242::1]:9051");
+ tt_str_op(describe_relay_port(smartlist_get(ports, 2)), OP_EQ,
+ "ORPort [4242::2]:9052");
+ tt_str_op(describe_relay_port(smartlist_get(ports, 3)), OP_EQ,
+ "ORPort 9050");
+
+ done:
+ SMARTLIST_FOREACH(ports,port_cfg_t *,pf,port_cfg_free(pf));
+ smartlist_free(ports);
+ config_free_lines(config_port);
+}
+
+static void
+test_config_multifamily_port(void *arg)
+{
+ (void) arg;
+
+ config_line_t *config_port = NULL;
+ smartlist_t *ports = smartlist_new();
+
+ config_line_append(&config_port, "SocksPort", "9050");
+ config_line_append(&config_port, "SocksPort", "[::1]:9050");
+
+ // Parse IPv4, then IPv6.
+ port_parse_config(ports, config_port, "SOCKS", CONN_TYPE_AP_LISTENER,
+ "0.0.0.0", 9050, 0);
+
+ /* There should be 2 ports at this point that is:
+ * - 0.0.0.0:9050
+ * - [::1]:9050
+ */
+ tt_int_op(smartlist_len(ports), OP_EQ, 2);
+
+ done:
+ SMARTLIST_FOREACH(ports, port_cfg_t *, cfg, port_cfg_free(cfg));
+ smartlist_free(ports);
+ config_free_lines(config_port);
+}
+
+#ifndef COCCI
#define CONFIG_TEST(name, flags) \
{ #name, test_config_ ## name, flags, NULL, NULL }
+#define CONFIG_TEST_SETUP(suffix, name, flags, setup, setup_data) \
+ { #name#suffix, test_config_ ## name, flags, setup, setup_data }
+#endif
+
struct testcase_t config_tests[] = {
CONFIG_TEST(adding_trusted_dir_server, TT_FORK),
CONFIG_TEST(adding_fallback_dir_server, TT_FORK),
@@ -5972,11 +7007,16 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(adding_dir_servers, TT_FORK),
CONFIG_TEST(default_dir_servers, TT_FORK),
CONFIG_TEST(default_fallback_dirs, 0),
- CONFIG_TEST(resolve_my_address, TT_FORK),
+ CONFIG_TEST_SETUP(_v4, find_my_address, TT_FORK,
+ &passthrough_setup, &addr_param_v4),
+ CONFIG_TEST_SETUP(_v6, find_my_address, TT_FORK,
+ &passthrough_setup, &addr_param_v6),
+ CONFIG_TEST(find_my_address_mixed, TT_FORK),
CONFIG_TEST(addressmap, 0),
CONFIG_TEST(parse_bridge_line, 0),
CONFIG_TEST(parse_transport_options_line, 0),
CONFIG_TEST(parse_transport_plugin_line, TT_FORK),
+ CONFIG_TEST(parse_tcp_proxy_line, TT_FORK),
CONFIG_TEST(check_or_create_data_subdir, TT_FORK),
CONFIG_TEST(write_to_data_subdir, TT_FORK),
CONFIG_TEST(fix_my_family, 0),
@@ -6004,6 +7044,8 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(include_flag_both_without, TT_FORK),
CONFIG_TEST(include_flag_torrc_only, TT_FORK),
CONFIG_TEST(include_flag_defaults_only, TT_FORK),
+ CONFIG_TEST(include_wildcards, 0),
+ CONFIG_TEST(include_hidden, 0),
CONFIG_TEST(dup_and_filter, 0),
CONFIG_TEST(check_bridge_distribution_setting_not_a_bridge, TT_FORK),
CONFIG_TEST(check_bridge_distribution_setting_valid, 0),
@@ -6012,5 +7054,9 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(include_opened_file_list, 0),
CONFIG_TEST(compute_max_mem_in_queues, 0),
CONFIG_TEST(extended_fmt, 0),
+ CONFIG_TEST(kvline_parse, 0),
+ CONFIG_TEST(getinfo_config_names, 0),
+ CONFIG_TEST(duplicate_orports, 0),
+ CONFIG_TEST(multifamily_port, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_confmgr.c b/src/test/test_confmgr.c
new file mode 100644
index 0000000000..a647b92e0a
--- /dev/null
+++ b/src/test/test_confmgr.c
@@ -0,0 +1,499 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/*
+ * Tests for confmgt.c's features that support multiple configuration
+ * formats and configuration objects.
+ */
+
+#define CONFMGT_PRIVATE
+#include "orconfig.h"
+
+#include "core/or/or.h"
+#include "lib/encoding/confline.h"
+#include "lib/confmgt/confmgt.h"
+#include "test/test.h"
+#include "test/log_test_helpers.h"
+
+/*
+ * Set up a few objects: a pasture_cfg is toplevel; it has a llama_cfg and an
+ * alpaca_cfg.
+ */
+
+typedef struct {
+ uint32_t magic;
+ char *address;
+ int opentopublic;
+ config_suite_t *subobjs;
+} pasture_cfg_t;
+
+typedef struct {
+ char *llamaname;
+ int cuteness;
+ uint32_t magic;
+ int eats_meat; /* deprecated; llamas are never carnivorous. */
+
+ char *description; // derived from other fields.
+} llama_cfg_t;
+
+typedef struct {
+ uint32_t magic;
+ int fuzziness;
+ char *alpacaname;
+ int n_wings; /* deprecated; alpacas don't have wings. */
+
+ int square_fuzziness; /* Derived from fuzziness. */
+} alpaca_cfg_t;
+
+/*
+ * Make the above into configuration objects.
+ */
+
+static pasture_cfg_t pasture_cfg_t_dummy;
+static llama_cfg_t llama_cfg_t_dummy;
+static alpaca_cfg_t alpaca_cfg_t_dummy;
+
+#define PV(name, type, dflt) \
+ CONFIG_VAR_ETYPE(pasture_cfg_t, #name, type, name, 0, dflt)
+#define LV(name, type, dflt) \
+ CONFIG_VAR_ETYPE(llama_cfg_t, #name, type, name, 0, dflt)
+#define AV(name, type, dflt) \
+ CONFIG_VAR_ETYPE(alpaca_cfg_t, #name, type, name, 0, dflt)
+static const config_var_t pasture_vars[] = {
+ PV(address, STRING, NULL),
+ PV(opentopublic, BOOL, "1"),
+ END_OF_CONFIG_VARS
+};
+static const config_var_t llama_vars[] =
+{
+ LV(llamaname, STRING, NULL),
+ LV(eats_meat, BOOL, NULL),
+ LV(cuteness, POSINT, "100"),
+ END_OF_CONFIG_VARS
+};
+static const config_var_t alpaca_vars[] =
+{
+ AV(alpacaname, STRING, NULL),
+ AV(fuzziness, POSINT, "50"),
+ AV(n_wings, POSINT, "0"),
+ END_OF_CONFIG_VARS
+};
+
+static config_deprecation_t llama_deprecations[] = {
+ { "eats_meat", "Llamas are herbivores." },
+ {NULL,NULL}
+};
+
+static config_deprecation_t alpaca_deprecations[] = {
+ { "n_wings", "Alpacas are quadrupeds." },
+ {NULL,NULL}
+};
+
+static int clear_llama_cfg_called = 0;
+static void
+clear_llama_cfg(const config_mgr_t *mgr, void *llamacfg)
+{
+ (void)mgr;
+ llama_cfg_t *lc = llamacfg;
+ tor_free(lc->description);
+ ++clear_llama_cfg_called;
+}
+
+static config_abbrev_t llama_abbrevs[] = {
+ { "gracia", "cuteness", 0, 0 },
+ { "gentillesse", "cuteness", 0, 0 },
+ { NULL, NULL, 0, 0 },
+};
+
+static int
+legacy_validate_pasture(const void *old_, void *obj, char **msg_out)
+{
+ const pasture_cfg_t *old = old_;
+ pasture_cfg_t *p = obj;
+
+ // llamas can't find their way home if the letters are lowercase.
+ if (p->address)
+ tor_strupper(p->address);
+
+ if (old && old->address &&
+ (!p->address || strcmp(old->address, p->address))) {
+ *msg_out = tor_strdup("You can't move a pasture.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+validate_llama(const void *obj, char **msg_out)
+{
+ const llama_cfg_t *llama = obj;
+ tor_assert(llama->magic == 0x11aa11);
+
+ if (! llama->llamaname || strlen(llama->llamaname) == 0) {
+ *msg_out = tor_strdup("A llama has no name!?");
+ return -1;
+ }
+
+ if (strspn(llama->llamaname, "0123456789") == strlen(llama->llamaname)) {
+ *msg_out = tor_strdup("It is not a number; it is a free llama!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+check_transition_alpaca(const void *old_, const void *new_, char **msg_out)
+{
+ const alpaca_cfg_t *old_alpaca = old_;
+ const alpaca_cfg_t *new_alpaca = new_;
+
+ tor_assert(old_alpaca && new_alpaca);
+ tor_assert(old_alpaca->magic == 0xa15aca);
+ tor_assert(new_alpaca->magic == 0xa15aca);
+
+ if (old_alpaca->fuzziness > new_alpaca->fuzziness) {
+ *msg_out = tor_strdup("An alpaca only becomes more fuzzy over time.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+post_normalize_llama(void *obj, char **msg_out)
+{
+ (void)msg_out;
+ llama_cfg_t *llama = obj;
+ tor_assert(llama->magic == 0x11aa11);
+ tor_assert(llama->llamaname); // we have already checked for a NULL name.
+ tor_free(llama->description);
+ tor_asprintf(&llama->description, "A llama called %s.", llama->llamaname);
+ return 0;
+}
+
+static int
+pre_normalize_alpaca(void *obj, char **msg_out)
+{
+ (void)msg_out;
+ alpaca_cfg_t *alpaca = obj;
+ tor_assert(alpaca->magic == 0xa15aca);
+ alpaca->square_fuzziness = alpaca->fuzziness * alpaca->fuzziness;
+ return 0;
+}
+
+static const config_format_t pasture_fmt = {
+ sizeof(pasture_cfg_t),
+ {
+ "pasture_cfg_t",
+ 8989,
+ offsetof(pasture_cfg_t, magic)
+ },
+ .vars = pasture_vars,
+ .has_config_suite = true,
+ .config_suite_offset = offsetof(pasture_cfg_t, subobjs),
+ .legacy_validate_fn = legacy_validate_pasture,
+};
+
+static const config_format_t llama_fmt = {
+ sizeof(llama_cfg_t),
+ {
+ "llama_cfg_t",
+ 0x11aa11,
+ offsetof(llama_cfg_t, magic)
+ },
+ .vars = llama_vars,
+ .deprecations = llama_deprecations,
+ .abbrevs = llama_abbrevs,
+ .clear_fn = clear_llama_cfg,
+ .validate_fn = validate_llama,
+ .post_normalize_fn = post_normalize_llama,
+};
+
+static const config_format_t alpaca_fmt = {
+ sizeof(alpaca_cfg_t),
+ {
+ "alpaca_cfg_t",
+ 0xa15aca,
+ offsetof(alpaca_cfg_t, magic)
+ },
+ .vars = alpaca_vars,
+ .deprecations = alpaca_deprecations,
+ .pre_normalize_fn = pre_normalize_alpaca,
+ .check_transition_fn = check_transition_alpaca,
+};
+
+#define LLAMA_IDX 0
+#define ALPACA_IDX 1
+
+static config_mgr_t *
+get_mgr(bool freeze)
+{
+ config_mgr_t *mgr = config_mgr_new(&pasture_fmt);
+ tt_int_op(LLAMA_IDX, OP_EQ, config_mgr_add_format(mgr, &llama_fmt));
+ tt_int_op(ALPACA_IDX, OP_EQ, config_mgr_add_format(mgr, &alpaca_fmt));
+ if (freeze)
+ config_mgr_freeze(mgr);
+ return mgr;
+
+ done:
+ config_mgr_free(mgr);
+ return NULL;
+}
+
+static void
+test_confmgr_init(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = get_mgr(true);
+ smartlist_t *vars = NULL;
+ tt_ptr_op(mgr, OP_NE, NULL);
+
+ vars = config_mgr_list_vars(mgr);
+ tt_int_op(smartlist_len(vars), OP_EQ, 8); // 8 vars total.
+
+ tt_str_op("cuteness", OP_EQ, config_find_option_name(mgr, "CUTENESS"));
+ tt_str_op("cuteness", OP_EQ, config_find_option_name(mgr, "GRACIA"));
+ smartlist_free(vars);
+
+ vars = config_mgr_list_deprecated_vars(mgr); // 2 deprecated vars.
+ tt_int_op(smartlist_len(vars), OP_EQ, 2);
+ tt_assert(smartlist_contains_string(vars, "eats_meat"));
+ tt_assert(smartlist_contains_string(vars, "n_wings"));
+
+ tt_str_op("Llamas are herbivores.", OP_EQ,
+ config_find_deprecation(mgr, "EATS_MEAT"));
+ tt_str_op("Alpacas are quadrupeds.", OP_EQ,
+ config_find_deprecation(mgr, "N_WINGS"));
+
+ done:
+ smartlist_free(vars);
+ config_mgr_free(mgr);
+}
+
+static void
+test_confmgr_magic(void *args)
+{
+ (void)args;
+ // Every time we build a manager, it is supposed to get a different magic
+ // number. Let's test that.
+ config_mgr_t *mgr1 = get_mgr(true);
+ config_mgr_t *mgr2 = get_mgr(true);
+ config_mgr_t *mgr3 = get_mgr(true);
+
+ pasture_cfg_t *p1 = NULL, *p2 = NULL, *p3 = NULL;
+
+ tt_assert(mgr1);
+ tt_assert(mgr2);
+ tt_assert(mgr3);
+
+ p1 = config_new(mgr1);
+ p2 = config_new(mgr2);
+ p3 = config_new(mgr3);
+
+ tt_assert(p1);
+ tt_assert(p2);
+ tt_assert(p3);
+
+ // By chance, two managers get the same magic with P=2^-32. Let's
+ // make sure that at least two of them are different, so that our
+ // odds of a false positive are 1/2^-64.
+ tt_assert((p1->magic != p2->magic) || (p2->magic != p3->magic));
+
+ done:
+ config_free(mgr1, p1);
+ config_free(mgr2, p2);
+ config_free(mgr3, p3);
+
+ config_mgr_free(mgr1);
+ config_mgr_free(mgr2);
+ config_mgr_free(mgr3);
+}
+
+static const char *simple_pasture =
+ "LLamaname hugo\n"
+ "Alpacaname daphne\n"
+ "gentillesse 42\n"
+ "address 123 Camelid ave\n";
+
+static void
+test_confmgr_parse(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = get_mgr(true);
+ pasture_cfg_t *p = config_new(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+
+ config_init(mgr, p); // set defaults.
+
+ int r = config_get_lines(simple_pasture, &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, p, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+
+ tt_int_op(p->opentopublic, OP_EQ, 1);
+ tt_str_op(p->address, OP_EQ, "123 Camelid ave");
+
+ // We are using this API directly; modules outside confparse will, in the
+ // future, not.
+ const alpaca_cfg_t *ac = config_mgr_get_obj(mgr, p, ALPACA_IDX);
+ const llama_cfg_t *lc = config_mgr_get_obj(mgr, p, LLAMA_IDX);
+ tt_str_op(lc->llamaname, OP_EQ, "hugo");
+ tt_str_op(ac->alpacaname, OP_EQ, "daphne");
+ tt_int_op(lc->cuteness, OP_EQ, 42);
+ tt_int_op(ac->fuzziness, OP_EQ, 50);
+
+ // We set the description for the llama here, so that the clear function
+ // can clear it. (Later we can do this in a verification function.)
+ clear_llama_cfg_called = 0;
+ llama_cfg_t *mut_lc = config_mgr_get_obj_mutable(mgr, p, LLAMA_IDX);
+ mut_lc->description = tor_strdup("A llama named Hugo.");
+ config_free(mgr, p);
+ tt_int_op(clear_llama_cfg_called, OP_EQ, 1);
+
+ done:
+ config_free_lines(lines);
+ config_free(mgr, p);
+ config_mgr_free(mgr);
+ tor_free(msg);
+}
+
+static void
+test_confmgr_dump(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = get_mgr(true);
+ pasture_cfg_t *p = config_new(mgr);
+ pasture_cfg_t *defaults = config_new(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+ char *s = NULL;
+
+ config_init(mgr, p); // set defaults.
+ config_init(mgr, defaults); // set defaults.
+
+ int r = config_get_lines(simple_pasture, &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, p, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+
+ s = config_dump(mgr, defaults, p, 1, 0);
+ tt_str_op("address 123 Camelid ave\n"
+ "alpacaname daphne\n"
+ "cuteness 42\n"
+ "llamaname hugo\n", OP_EQ, s);
+
+ done:
+ config_free_lines(lines);
+ config_free(mgr, p);
+ config_free(mgr, defaults);
+ config_mgr_free(mgr);
+
+ tor_free(msg);
+ tor_free(s);
+}
+
+static pasture_cfg_t *
+parse_and_validate(config_mgr_t *mgr,
+ const char *inp, const pasture_cfg_t *old, char **msg_out)
+{
+ pasture_cfg_t *p = config_new(mgr);
+ pasture_cfg_t *result = NULL;
+ config_line_t *lines = NULL;
+
+ config_init(mgr, p); // set defaults.
+ int r = config_get_lines(inp, &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, p, lines, 0, msg_out);
+ tt_int_op(r, OP_EQ, 0);
+ tor_free(*msg_out); // sets it to NULL
+ r = config_validate(mgr, old, p, msg_out);
+ if (r < 0)
+ goto done;
+
+ tt_ptr_op(*msg_out, OP_EQ, NULL);
+ result = p;
+ p = NULL; // prevent free
+ done:
+ config_free(mgr, p);
+ config_free_lines(lines);
+ return result;
+}
+
+static void
+test_confmgr_validate(void *arg)
+{
+ (void)arg;
+ char *msg = NULL;
+ config_mgr_t *mgr = get_mgr(true);
+ pasture_cfg_t *p_orig, *p=NULL;
+
+ p_orig = parse_and_validate(mgr, "Llamaname Quest\n"
+ "Address 99 camelid way\n"
+ "Fuzziness 8\n", NULL, &msg);
+ tt_assert(p_orig);
+
+ // Make sure normalization code was run.
+ const alpaca_cfg_t *ac0 = config_mgr_get_obj(mgr, p_orig, ALPACA_IDX);
+ const llama_cfg_t *lc0 = config_mgr_get_obj(mgr, p_orig, LLAMA_IDX);
+ tt_int_op(ac0->fuzziness, OP_EQ, 8);
+ tt_int_op(ac0->square_fuzziness, OP_EQ, 64);
+ tt_str_op(lc0->description, OP_EQ, "A llama called Quest.");
+ tt_str_op(p_orig->address, OP_EQ, "99 CAMELID WAY");
+
+ // try a bad llamaname.
+ p = parse_and_validate(mgr, "llamaname 123", p_orig, &msg);
+ tt_assert(!p);
+ tt_str_op(msg, OP_EQ, "It is not a number; it is a free llama!");
+ tor_free(msg);
+
+ // try a llamaname that would crash the post_normalize step, if it ran.
+ p = parse_and_validate(mgr, "", p_orig, &msg);
+ tt_assert(!p);
+ tt_str_op(msg, OP_EQ, "A llama has no name!?");
+ tor_free(msg);
+
+ // Verify that a transition to a less fuzzy alpaca fails.
+ p = parse_and_validate(mgr, "Llamaname Quest\n"
+ "Address 99 camelid way\n"
+ "Fuzziness 4\n", p_orig, &msg);
+ tt_assert(!p);
+ tt_str_op(msg, OP_EQ, "An alpaca only becomes more fuzzy over time.");
+ tor_free(msg);
+
+ // Try a transition to a more fuzzy alpaca; it should work fine.
+ p = parse_and_validate(mgr, "Llamaname Mercutio\n"
+ // the default fuzziness is 50
+ "Address 99 camelid way\n", p_orig, &msg);
+ tt_assert(p);
+ config_free(mgr, p);
+
+ // Verify that we can't move the pasture.
+ p = parse_and_validate(mgr, "Llamaname Montague\n"
+ // the default fuzziness is 50
+ "Address 99 ungulate st\n", p_orig, &msg);
+ tt_assert(!p);
+ tt_str_op(msg, OP_EQ, "You can't move a pasture.");
+
+ done:
+ config_free(mgr, p);
+ config_free(mgr, p_orig);
+ config_mgr_free(mgr);
+ tor_free(msg);
+}
+
+#define CONFMGR_TEST(name, flags) \
+ { #name, test_confmgr_ ## name, flags, NULL, NULL }
+
+struct testcase_t confmgr_tests[] = {
+ CONFMGR_TEST(init, 0),
+ CONFMGR_TEST(magic, 0),
+ CONFMGR_TEST(parse, 0),
+ CONFMGR_TEST(dump, 0),
+ CONFMGR_TEST(validate, 0),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_confparse.c b/src/test/test_confparse.c
new file mode 100644
index 0000000000..abd53dea68
--- /dev/null
+++ b/src/test/test_confparse.c
@@ -0,0 +1,1091 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/*
+ * Tests for confmgt.c module that we use to parse various
+ * configuration/state file types.
+ */
+
+#define CONFMGT_PRIVATE
+#include "orconfig.h"
+
+#include "core/or/or.h"
+#include "lib/encoding/confline.h"
+#include "feature/nodelist/routerset.h"
+#include "lib/confmgt/confmgt.h"
+#include "test/test.h"
+#include "test/log_test_helpers.h"
+
+#include "lib/confmgt/unitparse.h"
+
+typedef struct test_struct_t {
+ uint32_t magic;
+ char *s;
+ char *fn;
+ int pos;
+ int i;
+ int deprecated_int;
+ uint64_t u64;
+ int interval;
+ int msec_interval;
+ uint64_t mem;
+ double dbl;
+ int boolean;
+ int autobool;
+ time_t time;
+ smartlist_t *csv;
+ int csv_interval;
+ config_line_t *lines;
+ config_line_t *mixed_lines;
+ routerset_t *routerset;
+ int hidden_int;
+ config_line_t *mixed_hidden_lines;
+
+ config_line_t *extra_lines;
+} test_struct_t;
+
+static test_struct_t test_struct_t_dummy;
+
+#define VAR(varname,conftype,member,initvalue) \
+ CONFIG_VAR_ETYPE(test_struct_t, varname, conftype, member, 0, initvalue)
+#define V(member,conftype,initvalue) \
+ VAR(#member, conftype, member, initvalue)
+#define OBSOLETE(varname) \
+ CONFIG_VAR_OBSOLETE(varname)
+
+static const config_var_t test_vars[] = {
+ V(s, STRING, "hello"),
+ V(fn, FILENAME, NULL),
+ V(pos, POSINT, NULL),
+ V(i, INT, "-10"),
+ V(deprecated_int, INT, "3"),
+ V(u64, UINT64, NULL),
+ V(interval, INTERVAL, "10 seconds"),
+ V(msec_interval, MSEC_INTERVAL, "150 msec"),
+ V(mem, MEMUNIT, "10 MB"),
+ V(dbl, DOUBLE, NULL),
+ V(boolean, BOOL, "0"),
+ V(autobool, AUTOBOOL, "auto"),
+ V(time, ISOTIME, NULL),
+ V(csv, CSV, NULL),
+ V(csv_interval, CSV_INTERVAL, "5 seconds"),
+ V(lines, LINELIST, NULL),
+ VAR("MixedLines", LINELIST_V, mixed_lines, NULL),
+ VAR("LineTypeA", LINELIST_S, mixed_lines, NULL),
+ VAR("LineTypeB", LINELIST_S, mixed_lines, NULL),
+ OBSOLETE("obsolete"),
+ {
+ .member = { .name = "routerset",
+ .type = CONFIG_TYPE_EXTENDED,
+ .type_def = &ROUTERSET_type_defn,
+ .offset = offsetof(test_struct_t, routerset),
+ },
+ },
+ VAR("__HiddenInt", POSINT, hidden_int, "0"),
+ VAR("MixedHiddenLines", LINELIST_V, mixed_hidden_lines, NULL),
+ VAR("__HiddenLineA", LINELIST_S, mixed_hidden_lines, NULL),
+ VAR("VisibleLineB", LINELIST_S, mixed_hidden_lines, NULL),
+
+ END_OF_CONFIG_VARS,
+};
+
+static config_abbrev_t test_abbrevs[] = {
+ { "uint", "pos", 0, 0 },
+ { "float", "dbl", 0, 1 },
+ { NULL, NULL, 0, 0 }
+};
+
+static config_deprecation_t test_deprecation_notes[] = {
+ { "deprecated_int", "This integer is deprecated." },
+ { NULL, NULL }
+};
+
+static int
+test_validate_cb(const void *old_options, void *options, char **msg)
+{
+ (void)old_options;
+ (void)msg;
+ test_struct_t *ts = options;
+
+ if (ts->i == 0xbad) {
+ *msg = tor_strdup("bad value for i");
+ return -1;
+ }
+ return 0;
+}
+
+#define TEST_MAGIC 0x1337
+
+static const config_format_t test_fmt = {
+ .size = sizeof(test_struct_t),
+ .magic = {
+ "test_struct_t",
+ TEST_MAGIC,
+ offsetof(test_struct_t, magic),
+ },
+ .abbrevs = test_abbrevs,
+ .deprecations = test_deprecation_notes,
+ .vars = test_vars,
+ .legacy_validate_fn = test_validate_cb,
+};
+
+/* Make sure that config_init sets everything to the right defaults. */
+static void
+test_confparse_init(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = config_new(mgr);
+ config_init(mgr, tst);
+
+ // Make sure that options are initialized right. */
+ tt_str_op(tst->s, OP_EQ, "hello");
+ tt_ptr_op(tst->fn, OP_EQ, NULL);
+ tt_int_op(tst->pos, OP_EQ, 0);
+ tt_int_op(tst->i, OP_EQ, -10);
+ tt_int_op(tst->deprecated_int, OP_EQ, 3);
+ tt_u64_op(tst->u64, OP_EQ, 0);
+ tt_int_op(tst->interval, OP_EQ, 10);
+ tt_int_op(tst->msec_interval, OP_EQ, 150);
+ tt_u64_op(tst->mem, OP_EQ, 10 * 1024 * 1024);
+ tt_double_op(tst->dbl, OP_LT, .0000000001);
+ tt_double_op(tst->dbl, OP_GT, -0.0000000001);
+ tt_int_op(tst->boolean, OP_EQ, 0);
+ tt_int_op(tst->autobool, OP_EQ, -1);
+ tt_i64_op(tst->time, OP_EQ, 0);
+ tt_ptr_op(tst->csv, OP_EQ, NULL);
+ tt_int_op(tst->csv_interval, OP_EQ, 5);
+ tt_ptr_op(tst->lines, OP_EQ, NULL);
+ tt_ptr_op(tst->mixed_lines, OP_EQ, NULL);
+ tt_int_op(tst->hidden_int, OP_EQ, 0);
+
+ done:
+ config_free(mgr, tst);
+ config_mgr_free(mgr);
+}
+
+static const char simple_settings[] =
+ "s this is a \n"
+ "fn /simple/test of the\n"
+ "uint 77\n" // this is an abbrev
+ "i 3\n"
+ "u64 1000000000000 \n"
+ "interval 5 minutes \n"
+ "msec_interval 5 minutes \n"
+ "mem 10\n"
+ "dbl 6.060842\n"
+ "BOOLEAN 1\n"
+ "aUtObOOl 0\n"
+ "time 2019-06-14 13:58:51\n"
+ "csv configuration, parsing , system \n"
+ "csv_interval 10 seconds, 5 seconds, 10 hours\n"
+ "lines hello\n"
+ "LINES world\n"
+ "linetypea i d\n"
+ "linetypeb i c\n"
+ "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
+ "__hiddenint 11\n"
+ "__hiddenlineA XYZ\n"
+ "visiblelineB ABC\n";
+
+/* Return a configuration object set up from simple_settings above. */
+static test_struct_t *
+get_simple_config(const config_mgr_t *mgr)
+{
+ test_struct_t *result = NULL;
+ test_struct_t *tst = config_new(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+
+ config_init(mgr, tst);
+
+ int r = config_get_lines(simple_settings, &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, tst, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+
+ result = tst;
+ tst = NULL; // prevent free
+ done:
+ tor_free(msg);
+ config_free_lines(lines);
+ config_free(mgr, tst);
+ return result;
+}
+
+/* Make sure that config_assign can parse things. */
+static void
+test_confparse_assign_simple(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+
+ tt_str_op(tst->s, OP_EQ, "this is a");
+ tt_str_op(tst->fn, OP_EQ, "/simple/test of the");
+ tt_int_op(tst->pos, OP_EQ, 77);
+ tt_int_op(tst->i, OP_EQ, 3);
+ tt_int_op(tst->deprecated_int, OP_EQ, 3);
+ tt_u64_op(tst->u64, OP_EQ, UINT64_C(1000000000000));
+ tt_int_op(tst->interval, OP_EQ, 5 * 60);
+ tt_int_op(tst->msec_interval, OP_EQ, 5 * 60 * 1000);
+ tt_u64_op(tst->mem, OP_EQ, 10);
+ tt_double_op(tst->dbl, OP_LT, 6.060843);
+ tt_double_op(tst->dbl, OP_GT, 6.060841);
+ tt_int_op(tst->boolean, OP_EQ, 1);
+ tt_int_op(tst->autobool, OP_EQ, 0);
+ tt_i64_op(tst->time, OP_EQ, 1560520731);
+ tt_ptr_op(tst->csv, OP_NE, NULL);
+ tt_int_op(smartlist_len(tst->csv), OP_EQ, 3);
+ tt_str_op(smartlist_get(tst->csv, 0), OP_EQ, "configuration");
+ tt_str_op(smartlist_get(tst->csv, 1), OP_EQ, "parsing");
+ tt_str_op(smartlist_get(tst->csv, 2), OP_EQ, "system");
+ tt_int_op(tst->csv_interval, OP_EQ, 10);
+ tt_int_op(tst->hidden_int, OP_EQ, 11);
+
+ tt_assert(tst->lines);
+ tt_str_op(tst->lines->key, OP_EQ, "lines");
+ tt_str_op(tst->lines->value, OP_EQ, "hello");
+ tt_assert(tst->lines->next);
+ tt_str_op(tst->lines->next->key, OP_EQ, "lines");
+ tt_str_op(tst->lines->next->value, OP_EQ, "world");
+ tt_assert(!tst->lines->next->next);
+
+ tt_assert(tst->mixed_lines);
+ tt_str_op(tst->mixed_lines->key, OP_EQ, "LineTypeA");
+ tt_str_op(tst->mixed_lines->value, OP_EQ, "i d");
+ tt_assert(tst->mixed_lines->next);
+ tt_str_op(tst->mixed_lines->next->key, OP_EQ, "LineTypeB");
+ tt_str_op(tst->mixed_lines->next->value, OP_EQ, "i c");
+ tt_assert(!tst->mixed_lines->next->next);
+
+ tt_assert(tst->mixed_hidden_lines);
+ tt_str_op(tst->mixed_hidden_lines->key, OP_EQ, "__HiddenLineA");
+ tt_str_op(tst->mixed_hidden_lines->value, OP_EQ, "XYZ");
+ tt_assert(tst->mixed_hidden_lines->next);
+ tt_str_op(tst->mixed_hidden_lines->next->key, OP_EQ, "VisibleLineB");
+ tt_str_op(tst->mixed_hidden_lines->next->value, OP_EQ, "ABC");
+ tt_assert(!tst->mixed_hidden_lines->next->next);
+
+ tt_assert(config_check_ok(mgr, tst, LOG_ERR));
+
+ done:
+ config_free(mgr, tst);
+ config_mgr_free(mgr);
+}
+
+/* Try to assign to an obsolete option, and make sure we get a warning. */
+static void
+test_confparse_assign_obsolete(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+
+ config_init(mgr, tst);
+
+ int r = config_get_lines("obsolete option here",
+ &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ setup_capture_of_logs(LOG_WARN);
+ r = config_assign(mgr, tst, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ expect_single_log_msg_containing("Skipping obsolete configuration option");
+
+ done:
+ teardown_capture_of_logs();
+ config_free(mgr, tst);
+ config_free_lines(lines);
+ tor_free(msg);
+ config_mgr_free(mgr);
+}
+
+/* Try to assign to an deprecated option, and make sure we get a warning
+ * but the assignment works anyway. */
+static void
+test_confparse_assign_deprecated(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+
+ config_init(mgr, tst);
+
+ int r = config_get_lines("deprecated_int 7",
+ &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ setup_capture_of_logs(LOG_WARN);
+ r = config_assign(mgr, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ expect_single_log_msg_containing("This integer is deprecated.");
+
+ tt_int_op(tst->deprecated_int, OP_EQ, 7);
+
+ tt_assert(config_check_ok(mgr, tst, LOG_ERR));
+
+ done:
+ teardown_capture_of_logs();
+ config_free(mgr, tst);
+ config_free_lines(lines);
+ tor_free(msg);
+ config_mgr_free(mgr);
+}
+
+/* Try to re-assign an option name that has been deprecated in favor of
+ * another. */
+static void
+test_confparse_assign_replaced(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+
+ config_init(mgr, tst);
+
+ int r = config_get_lines("float 1000\n", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ setup_capture_of_logs(LOG_WARN);
+ r = config_assign(mgr, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ expect_single_log_msg_containing("use 'dbl' instead.");
+
+ tt_double_op(tst->dbl, OP_GT, 999.999);
+ tt_double_op(tst->dbl, OP_LT, 1000.001);
+
+ done:
+ teardown_capture_of_logs();
+ config_free(mgr, tst);
+ config_free_lines(lines);
+ tor_free(msg);
+ config_mgr_free(mgr);
+}
+
+/* Try to set a linelist value with no option. */
+static void
+test_confparse_assign_emptystring(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+
+ config_init(mgr, tst);
+
+ int r = config_get_lines("lines\n", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ setup_capture_of_logs(LOG_WARN);
+ r = config_assign(mgr, tst, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ expect_single_log_msg_containing("has no value");
+
+ done:
+ teardown_capture_of_logs();
+ config_free(mgr, tst);
+ config_free_lines(lines);
+ tor_free(msg);
+ config_mgr_free(mgr);
+}
+
+/* Try to set a the same option twice; make sure we get a warning. */
+static void
+test_confparse_assign_twice(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+
+ config_init(mgr, tst);
+
+ int r = config_get_lines("pos 10\n"
+ "pos 99\n", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ setup_capture_of_logs(LOG_WARN);
+ r = config_assign(mgr, tst, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ expect_single_log_msg_containing("used more than once");
+
+ done:
+ teardown_capture_of_logs();
+ config_free(mgr, tst);
+ config_free_lines(lines);
+ tor_free(msg);
+ config_mgr_free(mgr);
+}
+
+typedef struct badval_test_t {
+ const char *cfg;
+ const char *expect_msg;
+} badval_test_t;
+
+/* Try to set an option and make sure that we get a failure and an expected
+ * warning. */
+static void
+test_confparse_assign_badval(void *arg)
+{
+ const badval_test_t *bt = arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+
+ config_init(mgr, tst);
+
+ int r = config_get_lines(bt->cfg, &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ setup_capture_of_logs(LOG_WARN);
+ r = config_assign(mgr, tst, lines, 0, &msg);
+ tt_int_op(r, OP_LT, 0);
+ tt_ptr_op(msg, OP_NE, NULL);
+ if (! strstr(msg, bt->expect_msg)) {
+ TT_DIE(("'%s' did not contain '%s'" , msg, bt->expect_msg));
+ }
+
+ done:
+ teardown_capture_of_logs();
+ config_free(mgr, tst);
+ config_free_lines(lines);
+ tor_free(msg);
+ config_mgr_free(mgr);
+}
+
+/* Various arguments for badval test.
+ *
+ * Note that the expected warnings here are _very_ truncated, since we
+ * are writing these tests before a refactoring that we expect will
+ * change them.
+ */
+static const badval_test_t bv_notint = { "pos X\n", "malformed" };
+static const badval_test_t bv_negint = { "pos -10\n", "out of bounds" };
+static const badval_test_t bv_badu64 = { "u64 u64\n", "malformed" };
+static const badval_test_t bv_dbl1 = { "dbl xxx\n", "Could not convert" };
+static const badval_test_t bv_dbl2 = { "dbl 1.0 xx\n", "Could not convert" };
+static const badval_test_t bv_dbl3 = {
+ "dbl 1e-10000\n", "too small to express" };
+static const badval_test_t bv_dbl4 = {
+ "dbl 1e1000\n", "too large to express" };
+static const badval_test_t bv_dbl5 = {
+ "dbl -1e-10000\n", "too small to express" };
+static const badval_test_t bv_dbl6 = {
+ "dbl -1e1000\n", "too large to express" };
+static const badval_test_t bv_badcsvi1 =
+ { "csv_interval 10 wl\n", "malformed" };
+static const badval_test_t bv_badcsvi2 =
+ { "csv_interval cl,10\n", "malformed" };
+static const badval_test_t bv_nonoption = { "fnord 10\n", "Unknown option" };
+static const badval_test_t bv_badmem = { "mem 3 trits\n", "malformed" };
+static const badval_test_t bv_badbool = { "boolean 7\n", "Unrecognized value"};
+static const badval_test_t bv_badabool =
+ { "autobool 7\n", "Unrecognized value" };
+static const badval_test_t bv_badtime = { "time lunchtime\n", "Invalid time" };
+static const badval_test_t bv_virt = { "MixedLines 7\n", "virtual option" };
+static const badval_test_t bv_rs = { "Routerset 2.2.2.2.2\n", "Invalid" };
+static const badval_test_t bv_big_interval =
+ { "interval 1000 months", "too large" };
+
+/* Try config_dump(), and make sure it behaves correctly */
+static void
+test_confparse_dump(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+ char *dumped = NULL;
+
+ /* Minimal version. */
+ dumped = config_dump(mgr, NULL, tst, 1, 0);
+ tt_str_op(dumped, OP_EQ,
+ "autobool 0\n"
+ "boolean 1\n"
+ "csv configuration,parsing,system\n"
+ "csv_interval 10\n"
+ "dbl 6.060842\n"
+ "fn /simple/test of the\n"
+ "i 3\n"
+ "interval 300\n"
+ "lines hello\n"
+ "lines world\n"
+ "mem 10\n"
+ "VisibleLineB ABC\n"
+ "LineTypeA i d\n"
+ "LineTypeB i c\n"
+ "msec_interval 300000\n"
+ "pos 77\n"
+ "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
+ "s this is a\n"
+ "time 2019-06-14 13:58:51\n"
+ "u64 1000000000000\n");
+
+ tor_free(dumped);
+ dumped = config_dump(mgr, NULL, tst, 0, 0);
+ tt_str_op(dumped, OP_EQ,
+ "autobool 0\n"
+ "boolean 1\n"
+ "csv configuration,parsing,system\n"
+ "csv_interval 10\n"
+ "dbl 6.060842\n"
+ "deprecated_int 3\n"
+ "fn /simple/test of the\n"
+ "i 3\n"
+ "interval 300\n"
+ "lines hello\n"
+ "lines world\n"
+ "mem 10\n"
+ "VisibleLineB ABC\n"
+ "LineTypeA i d\n"
+ "LineTypeB i c\n"
+ "msec_interval 300000\n"
+ "pos 77\n"
+ "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
+ "s this is a\n"
+ "time 2019-06-14 13:58:51\n"
+ "u64 1000000000000\n");
+
+ /* commented */
+ tor_free(dumped);
+ dumped = config_dump(mgr, NULL, tst, 0, 1);
+ tt_str_op(dumped, OP_EQ,
+ "autobool 0\n"
+ "boolean 1\n"
+ "csv configuration,parsing,system\n"
+ "csv_interval 10\n"
+ "dbl 6.060842\n"
+ "# deprecated_int 3\n"
+ "fn /simple/test of the\n"
+ "i 3\n"
+ "interval 300\n"
+ "lines hello\n"
+ "lines world\n"
+ "mem 10\n"
+ "VisibleLineB ABC\n"
+ "LineTypeA i d\n"
+ "LineTypeB i c\n"
+ "msec_interval 300000\n"
+ "pos 77\n"
+ "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
+ "s this is a\n"
+ "time 2019-06-14 13:58:51\n"
+ "u64 1000000000000\n");
+
+ done:
+ config_free(mgr, tst);
+ tor_free(dumped);
+ config_mgr_free(mgr);
+}
+
+/* Try confparse_reset_line(), and make sure it behaves correctly */
+static void
+test_confparse_reset(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+
+ config_reset_line(mgr, tst, "interval", 0);
+ tt_int_op(tst->interval, OP_EQ, 0);
+
+ config_reset_line(mgr, tst, "interval", 1);
+ tt_int_op(tst->interval, OP_EQ, 10);
+
+ tt_ptr_op(tst->routerset, OP_NE, NULL);
+ config_reset_line(mgr, tst, "routerset", 0);
+ tt_ptr_op(tst->routerset, OP_EQ, NULL);
+
+ done:
+ config_free(mgr, tst);
+ config_mgr_free(mgr);
+}
+
+/* Try setting options a second time on a config object, and make sure
+ * it behaves correctly. */
+static void
+test_confparse_reassign(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL, *rs = NULL;
+
+ int r = config_get_lines(
+ "s eleven\n"
+ "i 12\n"
+ "lines 13\n"
+ "csv 14,15\n"
+ "routerset 127.0.0.1\n",
+ &lines, 0);
+ r = config_assign(mgr, tst,lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+
+ tt_str_op(tst->s, OP_EQ, "eleven");
+ tt_str_op(tst->fn, OP_EQ, "/simple/test of the"); // unchanged
+ tt_int_op(tst->pos, OP_EQ, 77); // unchanged
+ tt_int_op(tst->i, OP_EQ, 12);
+ tt_ptr_op(tst->lines, OP_NE, NULL);
+ tt_str_op(tst->lines->key, OP_EQ, "lines");
+ tt_str_op(tst->lines->value, OP_EQ, "13");
+ tt_ptr_op(tst->lines->next, OP_EQ, NULL);
+ tt_int_op(smartlist_len(tst->csv), OP_EQ, 2);
+ tt_str_op(smartlist_get(tst->csv, 0), OP_EQ, "14");
+ tt_str_op(smartlist_get(tst->csv, 1), OP_EQ, "15");
+
+ rs = routerset_to_string(tst->routerset);
+ tt_str_op(rs, OP_EQ, "127.0.0.1");
+
+ // Try again with the CLEAR_FIRST and USE_DEFAULTS flags
+ r = config_assign(mgr, tst, lines,
+ CAL_CLEAR_FIRST|CAL_USE_DEFAULTS, &msg);
+ tt_int_op(r, OP_EQ, 0);
+
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_str_op(tst->s, OP_EQ, "eleven");
+ // tt_ptr_op(tst->fn, OP_EQ, NULL); //XXXX why is this not cleared?
+ // tt_int_op(tst->pos, OP_EQ, 0); //XXXX why is this not cleared?
+ tt_int_op(tst->i, OP_EQ, 12);
+
+ done:
+ config_free(mgr, tst);
+ config_free_lines(lines);
+ tor_free(msg);
+ tor_free(rs);
+ config_mgr_free(mgr);
+}
+
+/* Try setting options a second time on a config object, using the +foo
+ * linelist-extending syntax. */
+static void
+test_confparse_reassign_extend(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+
+ int r = config_get_lines(
+ "+lines 13\n",
+ &lines, 1); // allow extended format.
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, tst,lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+
+ tt_assert(tst->lines);
+ tt_str_op(tst->lines->key, OP_EQ, "lines");
+ tt_str_op(tst->lines->value, OP_EQ, "hello");
+ tt_assert(tst->lines->next);
+ tt_str_op(tst->lines->next->key, OP_EQ, "lines");
+ tt_str_op(tst->lines->next->value, OP_EQ, "world");
+ tt_assert(tst->lines->next->next);
+ tt_str_op(tst->lines->next->next->key, OP_EQ, "lines");
+ tt_str_op(tst->lines->next->next->value, OP_EQ, "13");
+ tt_assert(tst->lines->next->next->next == NULL);
+ config_free_lines(lines);
+
+ r = config_get_lines(
+ "/lines\n",
+ &lines, 1); // allow extended format.
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, tst, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_assert(tst->lines == NULL);
+ config_free_lines(lines);
+
+ config_free(mgr, tst);
+ tst = get_simple_config(mgr);
+ r = config_get_lines(
+ "/lines away!\n",
+ &lines, 1); // allow extended format.
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, tst, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_assert(tst->lines == NULL);
+
+ done:
+ config_free(mgr, tst);
+ config_free_lines(lines);
+ tor_free(msg);
+ config_mgr_free(mgr);
+}
+
+/* Test out confparse_get_assigned(). */
+static void
+test_confparse_get_assigned(void *arg)
+{
+ (void)arg;
+
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = get_simple_config(mgr);
+ config_line_t *lines = NULL;
+
+ lines = config_get_assigned_option(mgr, tst, "I", 1);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "i");
+ tt_str_op(lines->value, OP_EQ, "3");
+ tt_assert(lines->next == NULL);
+ config_free_lines(lines);
+
+ lines = config_get_assigned_option(mgr, tst, "s", 1);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "s");
+ tt_str_op(lines->value, OP_EQ, "this is a");
+ tt_assert(lines->next == NULL);
+ config_free_lines(lines);
+
+ lines = config_get_assigned_option(mgr, tst, "obsolete", 1);
+ tt_assert(!lines);
+
+ lines = config_get_assigned_option(mgr, tst, "nonesuch", 1);
+ tt_assert(!lines);
+
+ lines = config_get_assigned_option(mgr, tst, "mixedlines", 1);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "LineTypeA");
+ tt_str_op(lines->value, OP_EQ, "i d");
+ tt_assert(lines->next);
+ tt_str_op(lines->next->key, OP_EQ, "LineTypeB");
+ tt_str_op(lines->next->value, OP_EQ, "i c");
+ tt_assert(lines->next->next == NULL);
+ config_free_lines(lines);
+
+ lines = config_get_assigned_option(mgr, tst, "linetypeb", 1);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "LineTypeB");
+ tt_str_op(lines->value, OP_EQ, "i c");
+ tt_assert(lines->next == NULL);
+ config_free_lines(lines);
+
+ tor_free(tst->s);
+ tst->s = tor_strdup("Hello\nWorld");
+ lines = config_get_assigned_option(mgr, tst, "s", 1);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "s");
+ tt_str_op(lines->value, OP_EQ, "\"Hello\\nWorld\"");
+ tt_assert(lines->next == NULL);
+ config_free_lines(lines);
+
+ done:
+ config_free(mgr, tst);
+ config_free_lines(lines);
+ config_mgr_free(mgr);
+}
+
+/* Another variant, which accepts and stores unrecognized lines.*/
+#define ETEST_MAGIC 13371337
+
+static struct_member_t extra = {
+ .name = "__extra",
+ .type = CONFIG_TYPE_LINELIST,
+ .offset = offsetof(test_struct_t, extra_lines),
+};
+
+static config_format_t etest_fmt = {
+ .size = sizeof(test_struct_t),
+ .magic = {
+ "test_struct_t (with extra lines)",
+ ETEST_MAGIC,
+ offsetof(test_struct_t, magic),
+ },
+ .abbrevs = test_abbrevs,
+ .deprecations = test_deprecation_notes,
+ .vars = test_vars,
+ .legacy_validate_fn = test_validate_cb,
+ .extra = &extra,
+};
+
+/* Try out the feature where we can store unrecognized lines and dump them
+ * again. (State files use this.) */
+static void
+test_confparse_extra_lines(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&etest_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = config_new(mgr);
+ config_line_t *lines = NULL;
+ char *msg = NULL, *dump = NULL;
+
+ config_init(mgr, tst);
+
+ int r = config_get_lines(
+ "unknotty addita\n"
+ "pos 99\n"
+ "wombat knish\n", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ r = config_assign(mgr, tst, lines, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+
+ tt_assert(tst->extra_lines);
+
+ dump = config_dump(mgr, NULL, tst, 1, 0);
+ tt_str_op(dump, OP_EQ,
+ "pos 99\n"
+ "unknotty addita\n"
+ "wombat knish\n");
+
+ done:
+ tor_free(msg);
+ tor_free(dump);
+ config_free_lines(lines);
+ config_free(mgr, tst);
+ config_mgr_free(mgr);
+}
+
+static void
+test_confparse_unitparse(void *args)
+{
+ (void)args;
+ /* spot-check a few memunit values. */
+ int ok = 3;
+ tt_u64_op(config_parse_memunit("100 MB", &ok), OP_EQ, 100<<20);
+ tt_assert(ok);
+ tt_u64_op(config_parse_memunit("100 TB", &ok), OP_EQ, UINT64_C(100)<<40);
+ tt_assert(ok);
+ // This is a floating-point value, but note that 1.5 can be represented
+ // precisely.
+ tt_u64_op(config_parse_memunit("1.5 MB", &ok), OP_EQ, 3<<19);
+ tt_assert(ok);
+
+ /* Try some good intervals and msec intervals */
+ tt_int_op(config_parse_interval("2 days", &ok), OP_EQ, 48*3600);
+ tt_assert(ok);
+ tt_int_op(config_parse_interval("1.5 hour", &ok), OP_EQ, 5400);
+ tt_assert(ok);
+ tt_u64_op(config_parse_interval("1 minute", &ok), OP_EQ, 60);
+ tt_assert(ok);
+ tt_int_op(config_parse_msec_interval("2 days", &ok), OP_EQ, 48*3600*1000);
+ tt_assert(ok);
+ tt_int_op(config_parse_msec_interval("10 msec", &ok), OP_EQ, 10);
+ tt_assert(ok);
+
+ /* Try a couple of unitless values. */
+ tt_int_op(config_parse_interval("10", &ok), OP_EQ, 10);
+ tt_assert(ok);
+ tt_u64_op(config_parse_interval("15.0", &ok), OP_EQ, 15);
+ tt_assert(ok);
+
+ /* u64 overflow */
+ tt_u64_op(config_parse_memunit("20000000 TB", &ok), OP_EQ, 0);
+ tt_assert(!ok);
+ // This test fails the double check as the float representing 15000000.5 TB
+ // is greater than (double) INT64_MAX
+ tt_u64_op(config_parse_memunit("15000000.5 TB", &ok), OP_EQ, 0);
+ tt_assert(!ok);
+ // 8388608.1 TB passes double check because it falls in the same float
+ // value as (double)INT64_MAX (which is 2^63) due to precision.
+ // But will fail the int check because the unsigned representation of
+ // the float, which is 2^63, is strictly greater than INT64_MAX (2^63-1)
+ tt_u64_op(config_parse_memunit("8388608.1 TB", &ok), OP_EQ, 0);
+ tt_assert(!ok);
+
+ /* negative float */
+ tt_u64_op(config_parse_memunit("-1.5 GB", &ok), OP_EQ, 0);
+ tt_assert(!ok);
+
+ /* i32 overflow */
+ tt_int_op(config_parse_interval("1000 months", &ok), OP_EQ, -1);
+ tt_assert(!ok);
+ tt_int_op(config_parse_msec_interval("4 weeks", &ok), OP_EQ, -1);
+ tt_assert(!ok);
+
+ /* bad units */
+ tt_u64_op(config_parse_memunit("7 nybbles", &ok), OP_EQ, 0);
+ tt_assert(!ok);
+ // XXXX these next two should return -1 according to the documentation.
+ tt_int_op(config_parse_interval("7 cowznofski", &ok), OP_EQ, 0);
+ tt_assert(!ok);
+ tt_int_op(config_parse_msec_interval("1 kalpa", &ok), OP_EQ, 0);
+ tt_assert(!ok);
+
+ done:
+ ;
+}
+
+static void
+test_confparse_check_ok_fail(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ config_mgr_freeze(mgr);
+ test_struct_t *tst = config_new(mgr);
+ tst->pos = -10;
+ tt_assert(! config_check_ok(mgr, tst, LOG_INFO));
+
+ done:
+ config_free(mgr, tst);
+ config_mgr_free(mgr);
+}
+
+static void
+test_confparse_list_vars(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ smartlist_t *vars = config_mgr_list_vars(mgr);
+ smartlist_t *varnames = smartlist_new();
+ char *joined = NULL;
+
+ tt_assert(vars);
+ SMARTLIST_FOREACH(vars, config_var_t *, cv,
+ smartlist_add(varnames, (void*)cv->member.name));
+ smartlist_sort_strings(varnames);
+ joined = smartlist_join_strings(varnames, "::", 0, NULL);
+ tt_str_op(joined, OP_EQ,
+ "LineTypeA::"
+ "LineTypeB::"
+ "MixedHiddenLines::"
+ "MixedLines::"
+ "VisibleLineB::"
+ "__HiddenInt::"
+ "__HiddenLineA::"
+ "autobool::"
+ "boolean::"
+ "csv::"
+ "csv_interval::"
+ "dbl::"
+ "deprecated_int::"
+ "fn::"
+ "i::"
+ "interval::"
+ "lines::"
+ "mem::"
+ "msec_interval::"
+ "obsolete::"
+ "pos::"
+ "routerset::"
+ "s::"
+ "time::"
+ "u64");
+
+ done:
+ tor_free(joined);
+ smartlist_free(varnames);
+ smartlist_free(vars);
+ config_mgr_free(mgr);
+}
+
+static void
+test_confparse_list_deprecated(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+ smartlist_t *vars = config_mgr_list_deprecated_vars(mgr);
+ char *joined = NULL;
+
+ tt_assert(vars);
+ smartlist_sort_strings(vars);
+ joined = smartlist_join_strings(vars, "::", 0, NULL);
+
+ tt_str_op(joined, OP_EQ, "deprecated_int");
+
+ done:
+ tor_free(joined);
+ smartlist_free(vars);
+ config_mgr_free(mgr);
+}
+
+static void
+test_confparse_find_option_name(void *arg)
+{
+ (void)arg;
+ config_mgr_t *mgr = config_mgr_new(&test_fmt);
+
+ // exact match
+ tt_str_op(config_find_option_name(mgr, "u64"), OP_EQ, "u64");
+ // case-insensitive match
+ tt_str_op(config_find_option_name(mgr, "S"), OP_EQ, "s");
+ tt_str_op(config_find_option_name(mgr, "linetypea"), OP_EQ, "LineTypeA");
+ // prefix match
+ tt_str_op(config_find_option_name(mgr, "deprec"), OP_EQ, "deprecated_int");
+ // explicit abbreviation
+ tt_str_op(config_find_option_name(mgr, "uint"), OP_EQ, "pos");
+ tt_str_op(config_find_option_name(mgr, "UINT"), OP_EQ, "pos");
+ // no match
+ tt_ptr_op(config_find_option_name(mgr, "absent"), OP_EQ, NULL);
+
+ done:
+ config_mgr_free(mgr);
+}
+
+#ifndef COCCI
+#define CONFPARSE_TEST(name, flags) \
+ { #name, test_confparse_ ## name, flags, NULL, NULL }
+
+#define BADVAL_TEST(name) \
+ { "badval_" #name, test_confparse_assign_badval, 0, \
+ &passthrough_setup, (void*)&bv_ ## name }
+#endif /* !defined(COCCI) */
+
+struct testcase_t confparse_tests[] = {
+ CONFPARSE_TEST(init, 0),
+ CONFPARSE_TEST(assign_simple, 0),
+ CONFPARSE_TEST(assign_obsolete, 0),
+ CONFPARSE_TEST(assign_deprecated, 0),
+ CONFPARSE_TEST(assign_replaced, 0),
+ CONFPARSE_TEST(assign_emptystring, 0),
+ CONFPARSE_TEST(assign_twice, 0),
+ BADVAL_TEST(notint),
+ BADVAL_TEST(negint),
+ BADVAL_TEST(badu64),
+ BADVAL_TEST(dbl1),
+ BADVAL_TEST(dbl2),
+ BADVAL_TEST(dbl3),
+ BADVAL_TEST(dbl4),
+ BADVAL_TEST(dbl5),
+ BADVAL_TEST(dbl6),
+ BADVAL_TEST(badcsvi1),
+ BADVAL_TEST(badcsvi2),
+ BADVAL_TEST(nonoption),
+ BADVAL_TEST(badmem),
+ BADVAL_TEST(badbool),
+ BADVAL_TEST(badabool),
+ BADVAL_TEST(badtime),
+ BADVAL_TEST(virt),
+ BADVAL_TEST(rs),
+ BADVAL_TEST(big_interval),
+ CONFPARSE_TEST(dump, 0),
+ CONFPARSE_TEST(reset, 0),
+ CONFPARSE_TEST(reassign, 0),
+ CONFPARSE_TEST(reassign_extend, 0),
+ CONFPARSE_TEST(get_assigned, 0),
+ CONFPARSE_TEST(extra_lines, 0),
+ CONFPARSE_TEST(unitparse, 0),
+ CONFPARSE_TEST(check_ok_fail, 0),
+ CONFPARSE_TEST(list_vars, 0),
+ CONFPARSE_TEST(list_deprecated, 0),
+ CONFPARSE_TEST(find_option_name, 0),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_connection.c b/src/test/test_connection.c
index 7234d01627..cf5626ead7 100644
--- a/src/test/test_connection.c
+++ b/src/test/test_connection.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -10,6 +10,8 @@
#include "core/or/or.h"
#include "test/test.h"
+#include "app/config/config.h"
+#include "app/config/or_options_st.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
#include "feature/hs/hs_common.h"
@@ -312,6 +314,25 @@ test_conn_download_status_teardown(const struct testcase_t *tc, void *arg)
return rv;
}
+static void *
+test_conn_proxy_connect_setup(const struct testcase_t *tc)
+{
+ return test_conn_get_proxy_or_connection(*(unsigned int *)tc->setup_data);
+}
+
+static int
+test_conn_proxy_connect_teardown(const struct testcase_t *tc, void *arg)
+{
+ (void)tc;
+ or_connection_t *conn = arg;
+
+ tt_assert(conn);
+ assert_connection_ok(&conn->base_, time(NULL));
+
+ done:
+ return 1;
+}
+
/* Like connection_ap_make_link(), but does much less */
static connection_t *
test_conn_get_linked_connection(connection_t *l_conn, uint8_t state)
@@ -360,6 +381,10 @@ static struct testcase_setup_t test_conn_download_status_st = {
test_conn_download_status_setup, test_conn_download_status_teardown
};
+static struct testcase_setup_t test_conn_proxy_connect_st = {
+ test_conn_proxy_connect_setup, test_conn_proxy_connect_teardown
+};
+
static void
test_conn_get_basic(void *arg)
{
@@ -789,6 +814,64 @@ test_conn_download_status(void *arg)
/* the teardown function removes all the connections in the global list*/;
}
+static void
+test_conn_https_proxy_connect(void *arg)
+{
+ size_t sz;
+ char *buf = NULL;
+ or_connection_t *conn = arg;
+
+ MOCK(connection_or_change_state, mock_connection_or_change_state);
+
+ tt_int_op(conn->base_.proxy_state, OP_EQ, PROXY_HTTPS_WANT_CONNECT_OK);
+
+ buf = buf_get_contents(conn->base_.outbuf, &sz);
+ tt_str_op(buf, OP_EQ, "CONNECT 127.0.0.1:12345 HTTP/1.0\r\n\r\n");
+
+ done:
+ UNMOCK(connection_or_change_state);
+ tor_free(buf);
+}
+
+static int handshake_start_called = 0;
+
+static int
+handshake_start(or_connection_t *conn, int receiving)
+{
+ (void)receiving;
+
+ tor_assert(conn);
+
+ handshake_start_called = 1;
+ return 0;
+}
+
+static void
+test_conn_haproxy_proxy_connect(void *arg)
+{
+ size_t sz;
+ char *buf = NULL;
+ or_connection_t *conn = arg;
+
+ MOCK(connection_or_change_state, mock_connection_or_change_state);
+ MOCK(connection_tls_start_handshake, handshake_start);
+
+ tt_int_op(conn->base_.proxy_state, OP_EQ, PROXY_HAPROXY_WAIT_FOR_FLUSH);
+
+ buf = buf_get_contents(conn->base_.outbuf, &sz);
+ tt_str_op(buf, OP_EQ, "PROXY TCP4 0.0.0.0 127.0.0.1 0 12345\r\n");
+
+ connection_or_finished_flushing(conn);
+
+ tt_int_op(conn->base_.proxy_state, OP_EQ, PROXY_CONNECTED);
+ tt_int_op(handshake_start_called, OP_EQ, 1);
+
+ done:
+ UNMOCK(connection_or_change_state);
+ UNMOCK(connection_tls_start_handshake);
+ tor_free(buf);
+}
+
static node_t test_node;
static node_t *
@@ -801,10 +884,8 @@ mock_node_get_mutable_by_id(const char *digest)
test_node.ri = &node_ri;
memset(test_node.identity, 'c', sizeof(test_node.identity));
- tor_addr_t ipv4_addr;
- tor_addr_parse(&ipv4_addr, "18.0.0.1");
- node_ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
- node_ri.or_port = 1;
+ tor_addr_parse(&node_ri.ipv4_addr, "18.0.0.1");
+ node_ri.ipv4_orport = 1;
return &test_node;
}
@@ -831,7 +912,8 @@ test_failed_orconn_tracker(void *arg)
/* Prepare the OR connection that will be used in this test */
or_connection_t or_conn;
- tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr, "18.0.0.1"));
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.canonical_orport.addr,
+ "18.0.0.1"));
tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.base_.addr, "18.0.0.1"));
or_conn.base_.port = 1;
memset(or_conn.identity_digest, 'c', sizeof(or_conn.identity_digest));
@@ -882,22 +964,148 @@ test_failed_orconn_tracker(void *arg)
;
}
+static void
+test_conn_describe(void *arg)
+{
+ (void)arg;
+ or_options_t *options = get_options_mutable();
+ options->SafeLogging_ = SAFELOG_SCRUB_ALL;
+
+ // Let's start with a listener connection since they're simple.
+ connection_t *conn = connection_new(CONN_TYPE_OR_LISTENER, AF_INET);
+ tor_addr_parse(&conn->addr, "44.22.11.11");
+ conn->port = 80;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR listener connection (ready) on 44.22.11.11:80");
+ // If the address is unspec, we should still work.
+ tor_addr_make_unspec(&conn->addr);
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR listener connection (ready) on <unset>:80");
+ // Try making the address null.
+ tor_addr_make_null(&conn->addr, AF_INET);
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR listener connection (ready) on 0.0.0.0:80");
+ // What if the address is uninitialized? (This can happen if we log about the
+ // connection before we set the address.)
+ memset(&conn->addr, 0, sizeof(conn->addr));
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR listener connection (ready) on <unset>:80");
+ connection_free_minimal(conn);
+
+ // Try a unix socket.
+ conn = connection_new(CONN_TYPE_CONTROL_LISTENER, AF_UNIX);
+ conn->address = tor_strdup("/a/path/that/could/exist");
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Control listener connection (ready) on /a/path/that/could/exist");
+ connection_free_minimal(conn);
+
+ // Try an IPv6 address.
+ conn = connection_new(CONN_TYPE_AP_LISTENER, AF_INET6);
+ tor_addr_parse(&conn->addr, "ff00::3");
+ conn->port = 9050;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Socks listener connection (ready) on [ff00::3]:9050");
+ connection_free_minimal(conn);
+
+ // Now let's mess with exit connections. They have some special issues.
+ options->SafeLogging_ = SAFELOG_SCRUB_NONE;
+ conn = connection_new(CONN_TYPE_EXIT, AF_INET);
+ // If address and state are unset, we should say SOMETHING.
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Exit connection (uninitialized) to <unset> (DNS lookup pending)");
+ // Now suppose that the address is set but we haven't resolved the hostname.
+ conn->port = 443;
+ conn->address = tor_strdup("www.torproject.org");
+ conn->state = EXIT_CONN_STATE_RESOLVING;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Exit connection (waiting for dest info) to "
+ "www.torproject.org:443 (DNS lookup pending)");
+ // Now give it a hostname!
+ tor_addr_parse(&conn->addr, "192.168.8.8");
+ conn->state = EXIT_CONN_STATE_OPEN;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Exit connection (open) to 192.168.8.8:443");
+ // But what if safelogging is on?
+ options->SafeLogging_ = SAFELOG_SCRUB_RELAY;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Exit connection (open) to [scrubbed]");
+ connection_free_minimal(conn);
+
+ // Now at last we look at OR addresses, which are complicated.
+ conn = connection_new(CONN_TYPE_OR, AF_INET6);
+ conn->state = OR_CONN_STATE_OPEN;
+ conn->port = 8080;
+ tor_addr_parse(&conn->addr, "[ffff:3333:1111::2]");
+ // This should get scrubbed, since the lack of a set ID means we might be
+ // talking to a client.
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR connection (open) with [scrubbed]");
+ // But now suppose we aren't safelogging? We'll get the address then.
+ options->SafeLogging_ = SAFELOG_SCRUB_NONE;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR connection (open) with [ffff:3333:1111::2]:8080");
+ // Suppose we have an ID, so we know it isn't a client.
+ TO_OR_CONN(conn)->identity_digest[3] = 7;
+ options->SafeLogging_ = SAFELOG_SCRUB_RELAY; // back to safelogging.
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR connection (open) with [ffff:3333:1111::2]:8080 "
+ "ID=<none> RSA_ID=0000000700000000000000000000000000000000");
+ // Add a 'canonical address' that is the same as the one we have.
+ tor_addr_parse(&TO_OR_CONN(conn)->canonical_orport.addr,
+ "[ffff:3333:1111::2]");
+ TO_OR_CONN(conn)->canonical_orport.port = 8080;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR connection (open) with [ffff:3333:1111::2]:8080 "
+ "ID=<none> RSA_ID=0000000700000000000000000000000000000000");
+ // Add a different 'canonical address'
+ tor_addr_parse(&TO_OR_CONN(conn)->canonical_orport.addr,
+ "[ffff:3333:1111::8]");
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR connection (open) with [ffff:3333:1111::2]:8080 "
+ "ID=<none> RSA_ID=0000000700000000000000000000000000000000 "
+ "canonical_addr=[ffff:3333:1111::8]:8080");
+
+ // Clear identity_digest so that free_minimal won't complain.
+ memset(TO_OR_CONN(conn)->identity_digest, 0, DIGEST_LEN);
+
+ done:
+ connection_free_minimal(conn);
+}
+
+#ifndef COCCI
#define CONNECTION_TESTCASE(name, fork, setup) \
{ #name, test_conn_##name, fork, &setup, NULL }
-/* where arg is a string. */
-#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \
- { #name "_" arg, test_conn_##name, fork, &setup, (void *)arg }
+#define STR(x) #x
+/* where arg is an expression (constant, variable, compound expression) */
+#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;
+static const unsigned int PROXY_HAPROXY_ARG = PROXY_HAPROXY;
struct testcase_t connection_tests[] = {
CONNECTION_TESTCASE(get_basic, TT_FORK, test_conn_get_basic_st),
CONNECTION_TESTCASE(get_rend, TT_FORK, test_conn_get_rend_st),
CONNECTION_TESTCASE(get_rsrc, TT_FORK, test_conn_get_rsrc_st),
+
CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
test_conn_download_status_st, "microdesc"),
CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
test_conn_download_status_st, "ns"),
-//CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair),
+
+ CONNECTION_TESTCASE_ARG(https_proxy_connect, TT_FORK,
+ test_conn_proxy_connect_st, &PROXY_CONNECT_ARG),
+ CONNECTION_TESTCASE_ARG(haproxy_proxy_connect, TT_FORK,
+ test_conn_proxy_connect_st, &PROXY_HAPROXY_ARG),
+
+ //CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair),
{ "failed_orconn_tracker", test_failed_orconn_tracker, TT_FORK, NULL, NULL },
+ { "describe", test_conn_describe, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_connection.h b/src/test/test_connection.h
index 47a5599e5f..bf327c0a3d 100644
--- a/src/test/test_connection.h
+++ b/src/test/test_connection.h
@@ -1,13 +1,18 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#ifndef TOR_TEST_CONNECTION_H
+#define TOR_TEST_CONNECTION_H
+
/** Some constants used by test_connection and helpers */
#define TEST_CONN_FAMILY (AF_INET)
#define TEST_CONN_ADDRESS "127.0.0.1"
+#define TEST_CONN_ADDRESS_2 "127.0.0.2"
#define TEST_CONN_PORT (12345)
#define TEST_CONN_ADDRESS_PORT "127.0.0.1:12345"
-#define TEST_CONN_FD_INIT 50
+#define TEST_CONN_FD_INIT 0x10000
void test_conn_lookup_addr_helper(const char *address,
int family, tor_addr_t *addr);
+#endif /* !defined(TOR_TEST_CONNECTION_H) */
diff --git a/src/test/test_conscache.c b/src/test/test_conscache.c
index 095ff09350..c805774fa3 100644
--- a/src/test/test_conscache.c
+++ b/src/test/test_conscache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_consdiff.c b/src/test/test_consdiff.c
index 682ba5b970..242e2f7818 100644
--- a/src/test/test_consdiff.c
+++ b/src/test/test_consdiff.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2014, Daniel Martí
- * Copyright (c) 2014-2019, The Tor Project, Inc. */
+ * Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONSDIFF_PRIVATE
@@ -14,6 +14,39 @@
#define tt_str_eq_line(a,b) \
tt_assert(line_str_eq((b),(a)))
+static int
+consensus_split_lines_(smartlist_t *out, const char *s, memarea_t *area)
+{
+ size_t len = strlen(s);
+ return consensus_split_lines(out, s, len, area);
+}
+
+static int
+consensus_compute_digest_(const char *cons,
+ consensus_digest_t *digest_out)
+{
+ size_t len = strlen(cons);
+ char *tmp = tor_memdup(cons, len);
+ // We use memdup here to ensure that the input is NOT nul-terminated.
+ // This makes it likelier for us to spot bugs.
+ int r = consensus_compute_digest(tmp, len, digest_out);
+ tor_free(tmp);
+ return r;
+}
+
+static int
+consensus_compute_digest_as_signed_(const char *cons,
+ consensus_digest_t *digest_out)
+{
+ size_t len = strlen(cons);
+ char *tmp = tor_memdup(cons, len);
+ // We use memdup here to ensure that the input is NOT nul-terminated.
+ // This makes it likelier for us to spot bugs.
+ int r = consensus_compute_digest_as_signed(tmp, len, digest_out);
+ tor_free(tmp);
+ return r;
+}
+
static void
test_consdiff_smartlist_slice(void *arg)
{
@@ -58,7 +91,7 @@ test_consdiff_smartlist_slice_string_pos(void *arg)
/* Create a regular smartlist. */
(void)arg;
- consensus_split_lines(sl, "a\nd\nc\na\nb\n", area);
+ consensus_split_lines_(sl, "a\nd\nc\na\nb\n", area);
/* See that smartlist_slice_string_pos respects the bounds of the slice. */
sls = smartlist_slice(sl, 2, 5);
@@ -87,8 +120,8 @@ test_consdiff_lcs_lengths(void *arg)
int e_lengths2[] = { 0, 1, 1, 2, 3, 4 };
(void)arg;
- consensus_split_lines(sl1, "a\nb\nc\nd\ne\n", area);
- consensus_split_lines(sl2, "a\nc\nd\ni\ne\n", area);
+ consensus_split_lines_(sl1, "a\nb\nc\nd\ne\n", area);
+ consensus_split_lines_(sl2, "a\nc\nd\ni\ne\n", area);
sls1 = smartlist_slice(sl1, 0, -1);
sls2 = smartlist_slice(sl2, 0, -1);
@@ -119,10 +152,10 @@ test_consdiff_trim_slices(void *arg)
memarea_t *area = memarea_new();
(void)arg;
- consensus_split_lines(sl1, "a\nb\nb\nb\nd\n", area);
- consensus_split_lines(sl2, "a\nc\nc\nc\nd\n", area);
- consensus_split_lines(sl3, "a\nb\nb\nb\na\n", area);
- consensus_split_lines(sl4, "c\nb\nb\nb\nc\n", area);
+ consensus_split_lines_(sl1, "a\nb\nb\nb\nd\n", area);
+ consensus_split_lines_(sl2, "a\nc\nc\nc\nd\n", area);
+ consensus_split_lines_(sl3, "a\nb\nb\nb\na\n", area);
+ consensus_split_lines_(sl4, "c\nb\nb\nb\nc\n", area);
sls1 = smartlist_slice(sl1, 0, -1);
sls2 = smartlist_slice(sl2, 0, -1);
sls3 = smartlist_slice(sl3, 0, -1);
@@ -165,8 +198,8 @@ test_consdiff_set_changed(void *arg)
memarea_t *area = memarea_new();
(void)arg;
- consensus_split_lines(sl1, "a\nb\na\na\n", area);
- consensus_split_lines(sl2, "a\na\na\na\n", area);
+ consensus_split_lines_(sl1, "a\nb\na\na\n", area);
+ consensus_split_lines_(sl2, "a\na\na\na\n", area);
/* Length of sls1 is 0. */
sls1 = smartlist_slice(sl1, 0, 0);
@@ -240,8 +273,8 @@ test_consdiff_calc_changes(void *arg)
memarea_t *area = memarea_new();
(void)arg;
- consensus_split_lines(sl1, "a\na\na\na\n", area);
- consensus_split_lines(sl2, "a\na\na\na\n", area);
+ consensus_split_lines_(sl1, "a\na\na\na\n", area);
+ consensus_split_lines_(sl2, "a\na\na\na\n", area);
sls1 = smartlist_slice(sl1, 0, -1);
sls2 = smartlist_slice(sl2, 0, -1);
@@ -259,7 +292,7 @@ test_consdiff_calc_changes(void *arg)
tt_assert(!bitarray_is_set(changed2, 3));
smartlist_clear(sl2);
- consensus_split_lines(sl2, "a\nb\na\nb\n", area);
+ consensus_split_lines_(sl2, "a\nb\na\nb\n", area);
tor_free(sls1);
tor_free(sls2);
sls1 = smartlist_slice(sl1, 0, -1);
@@ -282,7 +315,7 @@ test_consdiff_calc_changes(void *arg)
bitarray_clear(changed1, 3);
smartlist_clear(sl2);
- consensus_split_lines(sl2, "b\nb\nb\nb\n", area);
+ consensus_split_lines_(sl2, "b\nb\nb\nb\n", area);
tor_free(sls1);
tor_free(sls2);
sls1 = smartlist_slice(sl1, 0, -1);
@@ -610,8 +643,8 @@ test_consdiff_gen_ed_diff(void *arg)
/* Test 'a', 'c' and 'd' together. See that it is done in reverse order. */
smartlist_clear(cons1);
smartlist_clear(cons2);
- consensus_split_lines(cons1, "A\nB\nC\nD\nE\n", area);
- consensus_split_lines(cons2, "A\nC\nO\nE\nU\n", area);
+ consensus_split_lines_(cons1, "A\nB\nC\nD\nE\n", area);
+ consensus_split_lines_(cons2, "A\nC\nO\nE\nU\n", area);
diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_NE, diff);
tt_int_op(7, OP_EQ, smartlist_len(diff));
@@ -627,8 +660,8 @@ test_consdiff_gen_ed_diff(void *arg)
smartlist_clear(cons1);
smartlist_clear(cons2);
- consensus_split_lines(cons1, "B\n", area);
- consensus_split_lines(cons2, "A\nB\n", area);
+ consensus_split_lines_(cons1, "B\n", area);
+ consensus_split_lines_(cons2, "A\nB\n", area);
diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_NE, diff);
tt_int_op(3, OP_EQ, smartlist_len(diff));
@@ -656,7 +689,7 @@ test_consdiff_apply_ed_diff(void *arg)
diff = smartlist_new();
setup_capture_of_logs(LOG_WARN);
- consensus_split_lines(cons1, "A\nB\nC\nD\nE\n", area);
+ consensus_split_lines_(cons1, "A\nB\nC\nD\nE\n", area);
/* Command without range. */
smartlist_add_linecpy(diff, area, "a");
@@ -829,7 +862,7 @@ test_consdiff_apply_ed_diff(void *arg)
smartlist_clear(diff);
/* Test appending text, 'a'. */
- consensus_split_lines(diff, "3a\nU\nO\n.\n0a\nV\n.\n", area);
+ consensus_split_lines_(diff, "3a\nU\nO\n.\n0a\nV\n.\n", area);
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_NE, cons2);
tt_int_op(8, OP_EQ, smartlist_len(cons2));
@@ -846,7 +879,7 @@ test_consdiff_apply_ed_diff(void *arg)
smartlist_free(cons2);
/* Test deleting text, 'd'. */
- consensus_split_lines(diff, "4d\n1,2d\n", area);
+ consensus_split_lines_(diff, "4d\n1,2d\n", area);
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_NE, cons2);
tt_int_op(2, OP_EQ, smartlist_len(cons2));
@@ -857,7 +890,7 @@ test_consdiff_apply_ed_diff(void *arg)
smartlist_free(cons2);
/* Test changing text, 'c'. */
- consensus_split_lines(diff, "4c\nT\nX\n.\n1,2c\nM\n.\n", area);
+ consensus_split_lines_(diff, "4c\nT\nX\n.\n1,2c\nM\n.\n", area);
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_NE, cons2);
tt_int_op(5, OP_EQ, smartlist_len(cons2));
@@ -871,7 +904,7 @@ test_consdiff_apply_ed_diff(void *arg)
smartlist_free(cons2);
/* Test 'a', 'd' and 'c' together. */
- consensus_split_lines(diff, "4c\nT\nX\n.\n2d\n0a\nM\n.\n", area);
+ consensus_split_lines_(diff, "4c\nT\nX\n.\n2d\n0a\nM\n.\n", area);
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_NE, cons2);
tt_int_op(6, OP_EQ, smartlist_len(cons2));
@@ -918,12 +951,12 @@ test_consdiff_gen_diff(void *arg)
);
tt_int_op(0, OP_EQ,
- consensus_compute_digest_as_signed(cons1_str, &digests1));
+ consensus_compute_digest_as_signed_(cons1_str, &digests1));
tt_int_op(0, OP_EQ,
- consensus_compute_digest(cons2_str, &digests2));
+ consensus_compute_digest_(cons2_str, &digests2));
- consensus_split_lines(cons1, cons1_str, area);
- consensus_split_lines(cons2, cons2_str, area);
+ consensus_split_lines_(cons1, cons1_str, area);
+ consensus_split_lines_(cons2, cons2_str, area);
diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2, area);
tt_ptr_op(NULL, OP_EQ, diff);
@@ -937,9 +970,9 @@ test_consdiff_gen_diff(void *arg)
"directory-signature foo bar\nbar\n"
);
tt_int_op(0, OP_EQ,
- consensus_compute_digest_as_signed(cons1_str, &digests1));
+ consensus_compute_digest_as_signed_(cons1_str, &digests1));
smartlist_clear(cons1);
- consensus_split_lines(cons1, cons1_str, area);
+ consensus_split_lines_(cons1, cons1_str, area);
diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2, area);
tt_ptr_op(NULL, OP_NE, diff);
tt_int_op(11, OP_EQ, smartlist_len(diff));
@@ -991,13 +1024,13 @@ test_consdiff_apply_diff(void *arg)
"directory-signature foo bar\nbar\n"
);
tt_int_op(0, OP_EQ,
- consensus_compute_digest(cons1_str, &digests1));
- consensus_split_lines(cons1, cons1_str, area);
+ consensus_compute_digest_(cons1_str, &digests1));
+ consensus_split_lines_(cons1, cons1_str, area);
/* 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");
@@ -1005,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);
@@ -1015,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);
@@ -1024,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);
@@ -1034,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);
@@ -1045,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
@@ -1062,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);
@@ -1182,4 +1215,3 @@ struct testcase_t consdiff_tests[] = {
CONSDIFF_LEGACY(apply_diff),
END_OF_TESTCASES
};
-
diff --git a/src/test/test_consdiffmgr.c b/src/test/test_consdiffmgr.c
index 254a5ba5d0..f4adf43549 100644
--- a/src/test/test_consdiffmgr.c
+++ b/src/test/test_consdiffmgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONSDIFFMGR_PRIVATE
@@ -21,6 +21,23 @@
#include "test/test.h"
#include "test/log_test_helpers.h"
+#define consdiffmgr_add_consensus consdiffmgr_add_consensus_nulterm
+
+static char *
+consensus_diff_apply_(const char *c, const char *d)
+{
+ size_t c_len = strlen(c);
+ size_t d_len = strlen(d);
+ // We use memdup here to ensure that the input is NOT nul-terminated.
+ // This makes it likelier for us to spot bugs.
+ char *c_tmp = tor_memdup(c, c_len);
+ char *d_tmp = tor_memdup(d, d_len);
+ char *result = consensus_diff_apply(c_tmp, c_len, d_tmp, d_len);
+ tor_free(c_tmp);
+ tor_free(d_tmp);
+ return result;
+}
+
// ============================== Setup/teardown the consdiffmgr
// These functions get run before/after each test in this module
@@ -102,7 +119,7 @@ typedef struct fake_work_queue_ent_t {
void (*reply_fn)(void *);
void *arg;
} fake_work_queue_ent_t;
-static struct workqueue_entry_s *
+static struct workqueue_entry_t *
mock_cpuworker_queue_work(workqueue_priority_t prio,
enum workqueue_reply_t (*fn)(void *, void *),
void (*reply_fn)(void *),
@@ -118,7 +135,7 @@ mock_cpuworker_queue_work(workqueue_priority_t prio,
ent->reply_fn = reply_fn;
ent->arg = arg;
smartlist_add(fake_cpuworker_queue, ent);
- return (struct workqueue_entry_s *)ent;
+ return (struct workqueue_entry_t *)ent;
}
static int
mock_cpuworker_run_work(void)
@@ -153,7 +170,8 @@ lookup_diff_from(consensus_cache_entry_t **out,
const char *str1)
{
uint8_t digest[DIGEST256_LEN];
- if (router_get_networkstatus_v3_sha3_as_signed(digest, str1)<0) {
+ if (router_get_networkstatus_v3_sha3_as_signed(digest,
+ str1, strlen(str1))<0) {
TT_FAIL(("Unable to compute sha3-as-signed"));
return CONSDIFF_NOT_FOUND;
}
@@ -175,14 +193,15 @@ lookup_apply_and_verify_diff(consensus_flavor_t flav,
consensus_cache_entry_incref(ent);
size_t size;
- char *diff_string = NULL;
- int r = uncompress_or_copy(&diff_string, &size, ent);
+ const char *diff_string = NULL;
+ char *diff_owned = NULL;
+ int r = uncompress_or_set_ptr(&diff_string, &size, &diff_owned, ent);
consensus_cache_entry_decref(ent);
if (diff_string == NULL || r < 0)
return -1;
- char *applied = consensus_diff_apply(str1, diff_string);
- tor_free(diff_string);
+ char *applied = consensus_diff_apply(str1, strlen(str1), diff_string, size);
+ tor_free(diff_owned);
if (applied == NULL)
return -1;
@@ -282,7 +301,8 @@ test_consdiffmgr_add(void *arg)
(void) arg;
time_t now = approx_time();
- char *body = NULL;
+ const char *body = NULL;
+ char *body_owned = NULL;
consensus_cache_entry_t *ent = NULL;
networkstatus_t *ns_tmp = fake_ns_new(FLAV_NS, now);
@@ -324,7 +344,7 @@ test_consdiffmgr_add(void *arg)
tt_assert(ent);
consensus_cache_entry_incref(ent);
size_t s;
- r = uncompress_or_copy(&body, &s, ent);
+ r = uncompress_or_set_ptr(&body, &s, &body_owned, ent);
tt_int_op(r, OP_EQ, 0);
tt_int_op(s, OP_EQ, 4);
tt_mem_op(body, OP_EQ, "quux", 4);
@@ -337,7 +357,7 @@ test_consdiffmgr_add(void *arg)
networkstatus_vote_free(ns_tmp);
teardown_capture_of_logs();
consensus_cache_entry_decref(ent);
- tor_free(body);
+ tor_free(body_owned);
}
static void
@@ -370,7 +390,8 @@ test_consdiffmgr_make_diffs(void *arg)
ns = fake_ns_new(FLAV_MICRODESC, now-3600);
md_ns_body = fake_ns_body_new(FLAV_MICRODESC, now-3600);
r = consdiffmgr_add_consensus(md_ns_body, ns);
- router_get_networkstatus_v3_sha3_as_signed(md_ns_sha3, md_ns_body);
+ router_get_networkstatus_v3_sha3_as_signed(md_ns_sha3, md_ns_body,
+ strlen(md_ns_body));
networkstatus_vote_free(ns);
tt_int_op(r, OP_EQ, 0);
@@ -414,7 +435,7 @@ test_consdiffmgr_make_diffs(void *arg)
r = consensus_cache_entry_get_body(diff, &diff_body, &diff_size);
tt_int_op(r, OP_EQ, 0);
diff_text = tor_memdup_nulterm(diff_body, diff_size);
- applied = consensus_diff_apply(md_ns_body, diff_text);
+ applied = consensus_diff_apply_(md_ns_body, diff_text);
tt_assert(applied);
tt_str_op(applied, OP_EQ, md_ns_body_2);
@@ -668,7 +689,7 @@ static void
test_consdiffmgr_cleanup_bad_valid_after(void *arg)
{
/* This will seem cleanable, but isn't, because its valid-after time is
- * misformed. */
+ * malformed. */
(void)arg;
config_line_t *labels = NULL;
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index aedd2f7a89..6072148d1b 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -96,6 +96,30 @@ test_container_smartlist_basic(void *arg)
tor_free(v555);
}
+/** Test SMARTLIST_FOREACH_REVERSE_BEGIN loop macro */
+static void
+test_container_smartlist_foreach_reverse(void *arg)
+{
+ smartlist_t *sl = smartlist_new();
+ int i;
+
+ (void) arg;
+
+ /* Add integers to smartlist in increasing order */
+ for (i=0;i<100;i++) {
+ smartlist_add(sl, (void*)(uintptr_t)i);
+ }
+
+ /* Pop them out in reverse and test their value */
+ SMARTLIST_FOREACH_REVERSE_BEGIN(sl, void*, k) {
+ i--;
+ tt_ptr_op(k, OP_EQ, (void*)(uintptr_t)i);
+ } SMARTLIST_FOREACH_END(k);
+
+ done:
+ smartlist_free(sl);
+}
+
/** Run unit tests for smartlist-of-strings functionality. */
static void
test_container_smartlist_strings(void *arg)
@@ -582,6 +606,66 @@ test_container_smartlist_ints_eq(void *arg)
smartlist_free(sl2);
}
+static void
+test_container_smartlist_grow(void *arg)
+{
+ (void)arg;
+ smartlist_t *sl = smartlist_new();
+ int i;
+ const char *s[] = { "first", "2nd", "3rd" };
+
+ /* case 1: starting from empty. */
+ smartlist_grow(sl, 10);
+ tt_int_op(10, OP_EQ, smartlist_len(sl));
+ for (i = 0; i < 10; ++i) {
+ tt_ptr_op(smartlist_get(sl, i), OP_EQ, NULL);
+ }
+
+ /* case 2: starting with a few elements, probably not reallocating. */
+ smartlist_free(sl);
+ sl = smartlist_new();
+ smartlist_add(sl, (char*)s[0]);
+ smartlist_add(sl, (char*)s[1]);
+ smartlist_add(sl, (char*)s[2]);
+ smartlist_grow(sl, 5);
+ tt_int_op(5, OP_EQ, smartlist_len(sl));
+ for (i = 0; i < 3; ++i) {
+ tt_ptr_op(smartlist_get(sl, i), OP_EQ, s[i]);
+ }
+ tt_ptr_op(smartlist_get(sl, 3), OP_EQ, NULL);
+ tt_ptr_op(smartlist_get(sl, 4), OP_EQ, NULL);
+
+ /* case 3: starting with a few elements, but reallocating. */
+ smartlist_free(sl);
+ sl = smartlist_new();
+ smartlist_add(sl, (char*)s[0]);
+ smartlist_add(sl, (char*)s[1]);
+ smartlist_add(sl, (char*)s[2]);
+ smartlist_grow(sl, 100);
+ tt_int_op(100, OP_EQ, smartlist_len(sl));
+ for (i = 0; i < 3; ++i) {
+ tt_ptr_op(smartlist_get(sl, i), OP_EQ, s[i]);
+ }
+ for (i = 3; i < 100; ++i) {
+ tt_ptr_op(smartlist_get(sl, i), OP_EQ, NULL);
+ }
+
+ /* case 4: shrinking doesn't happen. */
+ smartlist_free(sl);
+ sl = smartlist_new();
+ smartlist_add(sl, (char*)s[0]);
+ smartlist_add(sl, (char*)s[1]);
+ smartlist_add(sl, (char*)s[2]);
+ smartlist_grow(sl, 1);
+ tt_int_op(3, OP_EQ, smartlist_len(sl));
+ for (i = 0; i < 3; ++i) {
+ tt_ptr_op(smartlist_get(sl, i), OP_EQ, s[i]);
+ }
+
+ done:
+ smartlist_free(sl);
+}
+
/** Run unit tests for bitarray code */
static void
test_container_bitarray(void *arg)
@@ -922,6 +1006,10 @@ test_container_smartlist_remove(void *arg)
tt_ptr_op(smartlist_get(sl, 1), OP_EQ, &array[2]);
tt_ptr_op(smartlist_get(sl, 2), OP_EQ, &array[1]);
tt_ptr_op(smartlist_get(sl, 3), OP_EQ, &array[2]);
+ /* Ordinary code should never look at this pointer; we're doing it here
+ * to make sure that we really cleared the pointer we removed.
+ */
+ tt_ptr_op(sl->list[4], OP_EQ, NULL);
done:
smartlist_free(sl);
@@ -1281,12 +1369,14 @@ test_container_smartlist_strings_eq(void *arg)
struct testcase_t container_tests[] = {
CONTAINER_LEGACY(smartlist_basic),
CONTAINER_LEGACY(smartlist_strings),
+ CONTAINER_LEGACY(smartlist_foreach_reverse),
CONTAINER_LEGACY(smartlist_overlap),
CONTAINER_LEGACY(smartlist_digests),
CONTAINER_LEGACY(smartlist_join),
CONTAINER_LEGACY(smartlist_pos),
CONTAINER(smartlist_remove, 0),
CONTAINER(smartlist_ints_eq, 0),
+ CONTAINER(smartlist_grow, 0),
CONTAINER_LEGACY(bitarray),
CONTAINER_LEGACY(digestset),
CONTAINER_LEGACY(strmap),
diff --git a/src/test/test_controller.c b/src/test/test_controller.c
index 5b406e159b..49efeb5f88 100644
--- a/src/test/test_controller.c
+++ b/src/test/test_controller.c
@@ -1,62 +1,279 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define CONTROL_PRIVATE
+#define CONTROL_CMD_PRIVATE
+#define CONTROL_GETINFO_PRIVATE
#include "core/or/or.h"
+#include "app/config/config.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "feature/client/bridges.h"
#include "feature/control/control.h"
+#include "feature/control/control_cmd.h"
+#include "feature/control/control_getinfo.h"
+#include "feature/control/control_proto.h"
#include "feature/client/entrynodes.h"
+#include "feature/dircache/cached_dir_st.h"
+#include "feature/dircache/dirserv.h"
#include "feature/hs/hs_common.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/rend/rendservice.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/nodelist.h"
+#include "feature/stats/rephist.h"
#include "test/test.h"
#include "test/test_helpers.h"
#include "lib/net/resolve.h"
+#include "lib/encoding/confline.h"
+#include "lib/encoding/kvline.h"
#include "feature/control/control_connection_st.h"
+#include "feature/control/control_cmd_args_st.h"
#include "feature/dirclient/download_status_st.h"
#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/node_st.h"
+typedef struct {
+ const char *input;
+ const char *expected_parse;
+ const char *expected_error;
+} parser_testcase_t;
+
+typedef struct {
+ const control_cmd_syntax_t *syntax;
+ size_t n_testcases;
+ const parser_testcase_t *testcases;
+} parse_test_params_t;
+
+static char *
+control_cmd_dump_args(const control_cmd_args_t *result)
+{
+ buf_t *buf = buf_new();
+ buf_add_string(buf, "{ args=[");
+ if (result->args) {
+ if (smartlist_len(result->args)) {
+ buf_add_string(buf, " ");
+ }
+ SMARTLIST_FOREACH_BEGIN(result->args, const char *, s) {
+ const bool last = (s_sl_idx == smartlist_len(result->args)-1);
+ buf_add_printf(buf, "%s%s ",
+ escaped(s),
+ last ? "" : ",");
+ } SMARTLIST_FOREACH_END(s);
+ }
+ buf_add_string(buf, "]");
+ if (result->cmddata) {
+ buf_add_string(buf, ", obj=");
+ buf_add_string(buf, escaped(result->cmddata));
+ }
+ if (result->kwargs) {
+ buf_add_string(buf, ", { ");
+ const config_line_t *line;
+ for (line = result->kwargs; line; line = line->next) {
+ const bool last = (line->next == NULL);
+ buf_add_printf(buf, "%s=%s%s ", line->key, escaped(line->value),
+ last ? "" : ",");
+ }
+ buf_add_string(buf, "}");
+ }
+ buf_add_string(buf, " }");
+
+ char *encoded = buf_extract(buf, NULL);
+ buf_free(buf);
+ return encoded;
+}
+
+static void
+test_controller_parse_cmd(void *arg)
+{
+ const parse_test_params_t *params = arg;
+ control_cmd_args_t *result = NULL;
+ char *error = NULL;
+ char *encoded = NULL;
+
+ for (size_t i = 0; i < params->n_testcases; ++i) {
+ const parser_testcase_t *t = &params->testcases[i];
+ result = control_cmd_parse_args("EXAMPLE",
+ params->syntax,
+ strlen(t->input),
+ t->input,
+ &error);
+ // A valid test should expect exactly one parse or error.
+ tt_int_op((t->expected_parse == NULL), OP_NE,
+ (t->expected_error == NULL));
+ // We get a result or an error, not both.
+ tt_int_op((result == NULL), OP_EQ, (error != NULL));
+ // We got the one we expected.
+ tt_int_op((result == NULL), OP_EQ, (t->expected_parse == NULL));
+
+ if (result) {
+ encoded = control_cmd_dump_args(result);
+ tt_str_op(encoded, OP_EQ, t->expected_parse);
+ } else {
+ tt_str_op(error, OP_EQ, t->expected_error);
+ }
+
+ tor_free(error);
+ tor_free(encoded);
+ control_cmd_args_free(result);
+ }
+
+ done:
+ tor_free(error);
+ tor_free(encoded);
+ control_cmd_args_free(result);
+}
+
+#ifndef COCCI
+#define OK(inp, out) \
+ { inp "\r\n", out, NULL }
+#define ERR(inp, err) \
+ { inp "\r\n", NULL, err }
+
+#define TESTPARAMS(syntax, array) \
+ { &syntax, \
+ ARRAY_LENGTH(array), \
+ array }
+#endif /* !defined(COCCI) */
+
+static const parser_testcase_t one_to_three_tests[] = {
+ ERR("", "Need at least 1 argument(s)"),
+ ERR(" \t", "Need at least 1 argument(s)"),
+ OK("hello", "{ args=[ \"hello\" ] }"),
+ OK("hello world", "{ args=[ \"hello\", \"world\" ] }"),
+ OK("hello world", "{ args=[ \"hello\", \"world\" ] }"),
+ OK(" hello world", "{ args=[ \"hello\", \"world\" ] }"),
+ OK(" hello world ", "{ args=[ \"hello\", \"world\" ] }"),
+ OK("hello there world", "{ args=[ \"hello\", \"there\", \"world\" ] }"),
+ ERR("why hello there world", "Cannot accept more than 3 argument(s)"),
+ ERR("hello\r\nworld.\r\n.", "Unexpected body"),
+};
+
+static const control_cmd_syntax_t one_to_three_syntax = {
+ .min_args=1, .max_args=3
+};
+
+static const parse_test_params_t parse_one_to_three_params =
+ TESTPARAMS( one_to_three_syntax, one_to_three_tests );
+
+// =
+static const parser_testcase_t no_args_one_obj_tests[] = {
+ ERR("Hi there!\r\n.", "Cannot accept more than 0 argument(s)"),
+ ERR("", "Empty body"),
+ OK("\r\n", "{ args=[], obj=\"\\n\" }"),
+ OK("\r\nHello world\r\n", "{ args=[], obj=\"Hello world\\n\\n\" }"),
+ OK("\r\nHello\r\nworld\r\n", "{ args=[], obj=\"Hello\\nworld\\n\\n\" }"),
+ OK("\r\nHello\r\n..\r\nworld\r\n",
+ "{ args=[], obj=\"Hello\\n.\\nworld\\n\\n\" }"),
+};
+static const control_cmd_syntax_t no_args_one_obj_syntax = {
+ .min_args=0, .max_args=0,
+ .want_cmddata=true,
+};
+static const parse_test_params_t parse_no_args_one_obj_params =
+ TESTPARAMS( no_args_one_obj_syntax, no_args_one_obj_tests );
+
+static const parser_testcase_t no_args_kwargs_tests[] = {
+ OK("", "{ args=[] }"),
+ OK(" ", "{ args=[] }"),
+ OK("hello there=world", "{ args=[], { hello=\"\", there=\"world\" } }"),
+ OK("hello there=world today",
+ "{ args=[], { hello=\"\", there=\"world\", today=\"\" } }"),
+ ERR("=Foo", "Cannot parse keyword argument(s)"),
+};
+static const control_cmd_syntax_t no_args_kwargs_syntax = {
+ .min_args=0, .max_args=0,
+ .accept_keywords=true,
+ .kvline_flags=KV_OMIT_VALS
+};
+static const parse_test_params_t parse_no_args_kwargs_params =
+ TESTPARAMS( no_args_kwargs_syntax, no_args_kwargs_tests );
+
+static const char *one_arg_kwargs_allow_keywords[] = {
+ "Hello", "world", NULL
+};
+static const parser_testcase_t one_arg_kwargs_tests[] = {
+ ERR("", "Need at least 1 argument(s)"),
+ OK("Hi", "{ args=[ \"Hi\" ] }"),
+ ERR("hello there=world", "Unrecognized keyword argument \"there\""),
+ OK("Hi HELLO=foo", "{ args=[ \"Hi\" ], { HELLO=\"foo\" } }"),
+ OK("Hi world=\"bar baz\" hello ",
+ "{ args=[ \"Hi\" ], { world=\"bar baz\", hello=\"\" } }"),
+};
+static const control_cmd_syntax_t one_arg_kwargs_syntax = {
+ .min_args=1, .max_args=1,
+ .accept_keywords=true,
+ .allowed_keywords=one_arg_kwargs_allow_keywords,
+ .kvline_flags=KV_OMIT_VALS|KV_QUOTED,
+};
+static const parse_test_params_t parse_one_arg_kwargs_params =
+ TESTPARAMS( one_arg_kwargs_syntax, one_arg_kwargs_tests );
+
+static char *reply_str = NULL;
+/* Mock for control_write_reply that copies the string for inspection
+ * by tests */
+static void
+mock_control_write_reply(control_connection_t *conn, int code, int c,
+ const char *s)
+{
+ (void)conn;
+ (void)code;
+ (void)c;
+ tor_free(reply_str);
+ reply_str = tor_strdup(s);
+}
+
static void
test_add_onion_helper_keyarg_v3(void *arg)
{
int ret, hs_version;
add_onion_secret_key_t pk;
char *key_new_blob = NULL;
- char *err_msg = NULL;
const char *key_new_alg = NULL;
(void) arg;
+ MOCK(control_write_reply, mock_control_write_reply);
memset(&pk, 0, sizeof(pk));
/* Test explicit ED25519-V3 key generation. */
+ tor_free(reply_str);
ret = add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg,
&key_new_blob, &pk, &hs_version,
- &err_msg);
+ NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE);
tt_assert(pk.v3);
tt_str_op(key_new_alg, OP_EQ, "ED25519-V3");
tt_assert(key_new_blob);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
tor_free(pk.v3); pk.v3 = NULL;
tor_free(key_new_blob);
+ /* Test "BEST" key generation (Assumes BEST = ED25519-V3). */
+ tor_free(pk.v3); pk.v3 = NULL;
+ tor_free(key_new_blob);
+ ret = add_onion_helper_keyarg("NEW:BEST", 0, &key_new_alg, &key_new_blob,
+ &pk, &hs_version, NULL);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE);
+ tt_assert(pk.v3);
+ tt_str_op(key_new_alg, OP_EQ, "ED25519-V3");
+ tt_assert(key_new_blob);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
+
/* Test discarding the private key. */
+ tor_free(reply_str);
+ tor_free(pk.v3); pk.v3 = NULL;
+ tor_free(key_new_blob);
ret = add_onion_helper_keyarg("NEW:ED25519-V3", 1, &key_new_alg,
&key_new_blob, &pk, &hs_version,
- &err_msg);
+ NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE);
tt_assert(pk.v3);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
tor_free(pk.v3); pk.v3 = NULL;
tor_free(key_new_blob);
@@ -76,9 +293,10 @@ test_add_onion_helper_keyarg_v3(void *arg)
tor_asprintf(&key_blob, "ED25519-V3:%s", base64_sk);
tt_assert(key_blob);
+ tor_free(reply_str);
ret = add_onion_helper_keyarg(key_blob, 1, &key_new_alg,
&key_new_blob, &pk, &hs_version,
- &err_msg);
+ NULL);
tor_free(key_blob);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE);
@@ -86,7 +304,7 @@ test_add_onion_helper_keyarg_v3(void *arg)
tt_mem_op(pk.v3, OP_EQ, hex_sk, 64);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
tor_free(pk.v3); pk.v3 = NULL;
tor_free(key_new_blob);
}
@@ -94,7 +312,8 @@ test_add_onion_helper_keyarg_v3(void *arg)
done:
tor_free(pk.v3);
tor_free(key_new_blob);
- tor_free(err_msg);
+ tor_free(reply_str);
+ UNMOCK(control_write_reply);
}
static void
@@ -105,72 +324,61 @@ test_add_onion_helper_keyarg_v2(void *arg)
crypto_pk_t *pk1 = NULL;
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
- char *err_msg = NULL;
char *encoded = NULL;
char *arg_str = NULL;
(void) arg;
+ MOCK(control_write_reply, mock_control_write_reply);
memset(&pk, 0, sizeof(pk));
/* Test explicit RSA1024 key generation. */
+ tor_free(reply_str);
ret = add_onion_helper_keyarg("NEW:RSA1024", 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
- tt_int_op(ret, OP_EQ, 0);
- tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
- tt_assert(pk.v2);
- tt_str_op(key_new_alg, OP_EQ, "RSA1024");
- tt_assert(key_new_blob);
- tt_ptr_op(err_msg, OP_EQ, NULL);
-
- /* Test "BEST" key generation (Assumes BEST = RSA1024). */
- crypto_pk_free(pk.v2); pk.v2 = NULL;
- tor_free(key_new_blob);
- ret = add_onion_helper_keyarg("NEW:BEST", 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(pk.v2);
tt_str_op(key_new_alg, OP_EQ, "RSA1024");
tt_assert(key_new_blob);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
/* Test discarding the private key. */
crypto_pk_free(pk.v2); pk.v2 = NULL;
tor_free(key_new_blob);
- ret = add_onion_helper_keyarg("NEW:BEST", 1, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ ret = add_onion_helper_keyarg("NEW:RSA1024", 1, &key_new_alg, &key_new_blob,
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
/* Test generating a invalid key type. */
crypto_pk_free(pk.v2); pk.v2 = NULL;
ret = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, -1);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(!pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_assert(err_msg);
+ tt_assert(reply_str);
/* Test loading a RSA1024 key. */
- tor_free(err_msg);
+ tor_free(reply_str);
pk1 = pk_generate(0);
tt_int_op(0, OP_EQ, crypto_pk_base64_encode_private(pk1, &encoded));
tor_asprintf(&arg_str, "RSA1024:%s", encoded);
ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
tt_int_op(crypto_pk_cmp_keys(pk1, pk.v2), OP_EQ, 0);
/* Test loading a invalid key type. */
@@ -179,36 +387,37 @@ test_add_onion_helper_keyarg_v2(void *arg)
crypto_pk_free(pk.v2); pk.v2 = NULL;
tor_asprintf(&arg_str, "RSA512:%s", encoded);
ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, -1);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(!pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_assert(err_msg);
+ tt_assert(reply_str);
/* Test loading a invalid key. */
tor_free(arg_str);
crypto_pk_free(pk.v2); pk.v2 = NULL;
- tor_free(err_msg);
+ tor_free(reply_str);
encoded[strlen(encoded)/2] = '\0';
tor_asprintf(&arg_str, "RSA1024:%s", encoded);
ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, -1);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(!pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_assert(err_msg);
+ tt_assert(reply_str);
done:
crypto_pk_free(pk1);
crypto_pk_free(pk.v2);
tor_free(key_new_blob);
- tor_free(err_msg);
+ tor_free(reply_str);
tor_free(encoded);
tor_free(arg_str);
+ UNMOCK(control_write_reply);
}
static void
@@ -362,49 +571,52 @@ static void
test_add_onion_helper_clientauth(void *arg)
{
rend_authorized_client_t *client = NULL;
- char *err_msg = NULL;
int created = 0;
(void)arg;
+ MOCK(control_write_reply, mock_control_write_reply);
/* Test "ClientName" only. */
- client = add_onion_helper_clientauth("alice", &created, &err_msg);
+ tor_free(reply_str);
+ client = add_onion_helper_clientauth("alice", &created, NULL);
tt_assert(client);
tt_assert(created);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
rend_authorized_client_free(client);
/* Test "ClientName:Blob" */
+ tor_free(reply_str);
client = add_onion_helper_clientauth("alice:475hGBHPlq7Mc0cRZitK/B",
- &created, &err_msg);
+ &created, NULL);
tt_assert(client);
tt_assert(!created);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
rend_authorized_client_free(client);
/* Test invalid client names */
+ tor_free(reply_str);
client = add_onion_helper_clientauth("no*asterisks*allowed", &created,
- &err_msg);
+ NULL);
tt_ptr_op(client, OP_EQ, NULL);
- tt_assert(err_msg);
- tor_free(err_msg);
+ tt_assert(reply_str);
/* Test invalid auth cookie */
- client = add_onion_helper_clientauth("alice:12345", &created, &err_msg);
+ tor_free(reply_str);
+ client = add_onion_helper_clientauth("alice:12345", &created, NULL);
tt_ptr_op(client, OP_EQ, NULL);
- tt_assert(err_msg);
- tor_free(err_msg);
+ tt_assert(reply_str);
/* Test invalid syntax */
+ tor_free(reply_str);
client = add_onion_helper_clientauth(":475hGBHPlq7Mc0cRZitK/B", &created,
- &err_msg);
+ NULL);
tt_ptr_op(client, OP_EQ, NULL);
- tt_assert(err_msg);
- tor_free(err_msg);
+ tt_assert(reply_str);
done:
rend_authorized_client_free(client);
- tor_free(err_msg);
+ tor_free(reply_str);
+ UNMOCK(control_write_reply);
}
/* Mocks and data/variables used for GETINFO download status tests */
@@ -1485,6 +1697,138 @@ test_download_status_bridge(void *arg)
return;
}
+/** Mock cached consensus */
+static cached_dir_t *mock_ns_consensus_cache;
+static cached_dir_t *mock_microdesc_consensus_cache;
+
+/** Mock the function that retrieves consensus from cache. These use a
+ * global variable so that they can be cleared from within the test.
+ * The actual code retains the pointer to the consensus data, but
+ * we are doing this here, to prevent memory leaks
+ * from within the tests */
+static cached_dir_t *
+mock_dirserv_get_consensus(const char *flavor_name)
+{
+ if (!strcmp(flavor_name, "ns")) {
+ mock_ns_consensus_cache = tor_malloc_zero(sizeof(cached_dir_t));
+ mock_ns_consensus_cache->dir = tor_strdup("mock_ns_consensus");
+ return mock_ns_consensus_cache;
+ } else {
+ mock_microdesc_consensus_cache = tor_malloc_zero(sizeof(cached_dir_t));
+ mock_microdesc_consensus_cache->dir = tor_strdup(
+ "mock_microdesc_consensus");
+ return mock_microdesc_consensus_cache;
+ }
+}
+
+/** Mock the function that retrieves consensuses
+ * from a files in the directory. */
+static tor_mmap_t *
+mock_tor_mmap_file(const char* filename)
+{
+ tor_mmap_t *res;
+ res = tor_malloc_zero(sizeof(tor_mmap_t));
+ if (strstr(filename, "cached-consensus") != NULL) {
+ res->data = "mock_ns_consensus";
+ } else if (strstr(filename, "cached-microdesc-consensus") != NULL) {
+ res->data = "mock_microdesc_consensus";
+ } else {
+ res->data = ".";
+ }
+ res->size = strlen(res->data);
+ return res;
+}
+
+/** Mock the function that clears file data
+ * loaded into the memory */
+static int
+mock_tor_munmap_file(tor_mmap_t *handle)
+{
+ tor_free(handle);
+ return 0;
+}
+
+static void
+test_getinfo_helper_current_consensus_from_file(void *arg)
+{
+ /* We just need one of these to pass, it doesn't matter what's in it */
+ control_connection_t dummy;
+ /* Get results out */
+ char *answer = NULL;
+ const char *errmsg = NULL;
+
+ (void)arg;
+
+ MOCK(tor_mmap_file, mock_tor_mmap_file);
+ MOCK(tor_munmap_file, mock_tor_munmap_file);
+
+ getinfo_helper_dir(&dummy,
+ "dir/status-vote/current/consensus",
+ &answer,
+ &errmsg);
+ tt_str_op(answer, OP_EQ, "mock_ns_consensus");
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_dir(&dummy,
+ "dir/status-vote/current/consensus-microdesc",
+ &answer,
+ &errmsg);
+ tt_str_op(answer, OP_EQ, "mock_microdesc_consensus");
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ errmsg = NULL;
+
+ done:
+ tor_free(answer);
+ UNMOCK(tor_mmap_file);
+ UNMOCK(tor_munmap_file);
+ return;
+}
+
+static void
+test_getinfo_helper_current_consensus_from_cache(void *arg)
+{
+ /* We just need one of these to pass, it doesn't matter what's in it */
+ control_connection_t dummy;
+ /* Get results out */
+ char *answer = NULL;
+ const char *errmsg = NULL;
+
+ (void)arg;
+ or_options_t *options = get_options_mutable();
+ options->FetchUselessDescriptors = 1;
+ MOCK(dirserv_get_consensus, mock_dirserv_get_consensus);
+
+ getinfo_helper_dir(&dummy,
+ "dir/status-vote/current/consensus",
+ &answer,
+ &errmsg);
+ tt_str_op(answer, OP_EQ, "mock_ns_consensus");
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tor_free(answer);
+ tor_free(mock_ns_consensus_cache->dir);
+ tor_free(mock_ns_consensus_cache);
+ errmsg = NULL;
+
+ getinfo_helper_dir(&dummy,
+ "dir/status-vote/current/consensus-microdesc",
+ &answer,
+ &errmsg);
+ tt_str_op(answer, OP_EQ, "mock_microdesc_consensus");
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tor_free(mock_microdesc_consensus_cache->dir);
+ tor_free(answer);
+ errmsg = NULL;
+
+ done:
+ options->FetchUselessDescriptors = 0;
+ tor_free(answer);
+ tor_free(mock_microdesc_consensus_cache);
+ UNMOCK(dirserv_get_consensus);
+ return;
+}
+
/** Set timeval to a mock date and time. This is necessary
* to make tor_gettimeofday() mockable. */
static void
@@ -1543,7 +1887,7 @@ test_current_time(void *arg)
static size_t n_nodelist_get_list = 0;
static smartlist_t *nodes = NULL;
-static smartlist_t *
+static const smartlist_t *
mock_nodelist_get_list(void)
{
n_nodelist_get_list++;
@@ -1614,7 +1958,257 @@ test_getinfo_md_all(void *arg)
return;
}
+static smartlist_t *reply_strs;
+
+static void
+mock_control_write_reply_list(control_connection_t *conn, int code, int c,
+ const char *s)
+{
+ (void)conn;
+ /* To make matching easier, don't append "\r\n" */
+ smartlist_add_asprintf(reply_strs, "%03d%c%s", code, c, s);
+}
+
+static void
+test_control_reply(void *arg)
+{
+ (void)arg;
+ smartlist_t *lines = smartlist_new();
+
+ MOCK(control_write_reply, mock_control_write_reply);
+
+ tor_free(reply_str);
+ control_reply_clear(lines);
+ control_reply_add_str(lines, 250, "FOO");
+ control_write_reply_lines(NULL, lines);
+ tt_str_op(reply_str, OP_EQ, "FOO");
+
+ tor_free(reply_str);
+ control_reply_clear(lines);
+ control_reply_add_done(lines);
+ control_write_reply_lines(NULL, lines);
+ tt_str_op(reply_str, OP_EQ, "OK");
+
+ tor_free(reply_str);
+ control_reply_clear(lines);
+ UNMOCK(control_write_reply);
+ MOCK(control_write_reply, mock_control_write_reply_list);
+ reply_strs = smartlist_new();
+ control_reply_add_one_kv(lines, 250, 0, "A", "B");
+ control_reply_add_one_kv(lines, 250, 0, "C", "D");
+ control_write_reply_lines(NULL, lines);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 2);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ, "250-A=B");
+ tt_str_op((char *)smartlist_get(reply_strs, 1), OP_EQ, "250 C=D");
+
+ control_reply_clear(lines);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+ control_reply_add_printf(lines, 250, "PROTOCOLINFO %d", 1);
+ control_reply_add_one_kv(lines, 250, KV_OMIT_VALS|KV_RAW, "AUTH", "");
+ control_reply_append_kv(lines, "METHODS", "COOKIE");
+ control_reply_append_kv(lines, "COOKIEFILE", escaped("/tmp/cookie"));
+ control_reply_add_done(lines);
+ control_write_reply_lines(NULL, lines);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 3);
+ tt_str_op((char *)smartlist_get(reply_strs, 0),
+ OP_EQ, "250-PROTOCOLINFO 1");
+ tt_str_op((char *)smartlist_get(reply_strs, 1),
+ OP_EQ, "250-AUTH METHODS=COOKIE COOKIEFILE=\"/tmp/cookie\"");
+ tt_str_op((char *)smartlist_get(reply_strs, 2),
+ OP_EQ, "250 OK");
+
+ done:
+ UNMOCK(control_write_reply);
+ tor_free(reply_str);
+ control_reply_free(lines);
+ if (reply_strs)
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_free(reply_strs);
+ return;
+}
+
+static void
+test_control_getconf(void *arg)
+{
+ (void)arg;
+ control_connection_t conn;
+ char *args = NULL;
+ int r = -1;
+
+ memset(&conn, 0, sizeof(conn));
+ conn.current_cmd = tor_strdup("GETCONF");
+
+ MOCK(control_write_reply, mock_control_write_reply_list);
+ reply_strs = smartlist_new();
+
+ args = tor_strdup("");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 1);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ, "250 OK");
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+ tor_free(args);
+
+ args = tor_strdup("NoSuch");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 1);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ,
+ "552 Unrecognized configuration key \"NoSuch\"");
+ tor_free(args);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+
+ args = tor_strdup("NoSuch1 NoSuch2");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 2);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ,
+ "552-Unrecognized configuration key \"NoSuch1\"");
+ tt_str_op((char *)smartlist_get(reply_strs, 1), OP_EQ,
+ "552 Unrecognized configuration key \"NoSuch2\"");
+ tor_free(args);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+
+ args = tor_strdup("ControlPort NoSuch");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ /* Valid keys ignored if there are any invalid ones */
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 1);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ,
+ "552 Unrecognized configuration key \"NoSuch\"");
+ tor_free(args);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+
+ args = tor_strdup("ClientOnly");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 1);
+ /* According to config.c, this is an exception for the unit tests */
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ, "250 ClientOnly=0");
+ tor_free(args);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+
+ args = tor_strdup("BridgeRelay ClientOnly");
+ r = handle_control_command(&conn, (uint32_t)strlen(args), args);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 2);
+ /* Change if config.c changes BridgeRelay default (unlikely) */
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ, "250-BridgeRelay=0");
+ tt_str_op((char *)smartlist_get(reply_strs, 1), OP_EQ, "250 ClientOnly=0");
+ tor_free(args);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+
+ done:
+ tor_free(conn.current_cmd);
+ tor_free(args);
+ UNMOCK(control_write_reply);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_free(reply_strs);
+}
+
+static int
+mock_rep_hist_get_circuit_handshake(uint16_t type)
+{
+ int ret;
+
+ switch (type) {
+ case ONION_HANDSHAKE_TYPE_NTOR:
+ ret = 80;
+ break;
+ case ONION_HANDSHAKE_TYPE_TAP:
+ ret = 86;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+test_stats(void *arg)
+{
+ /* We just need one of these to pass, it doesn't matter what's in it */
+ control_connection_t dummy;
+ /* Get results out */
+ char *answer = NULL;
+ const char *errmsg = NULL;
+
+ (void) arg;
+
+ /* We need these for returning the (mock) rephist. */
+ MOCK(rep_hist_get_circuit_handshake_requested,
+ mock_rep_hist_get_circuit_handshake);
+ MOCK(rep_hist_get_circuit_handshake_assigned,
+ mock_rep_hist_get_circuit_handshake);
+
+ /* NTor tests */
+ getinfo_helper_rephist(&dummy, "stats/ntor/requested",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "80");
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_rephist(&dummy, "stats/ntor/assigned",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "80");
+ tor_free(answer);
+ errmsg = NULL;
+
+ /* TAP tests */
+ getinfo_helper_rephist(&dummy, "stats/tap/requested",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "86");
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_rephist(&dummy, "stats/tap/assigned",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "86");
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_rephist(&dummy, "stats/tap/onion_circuits_ddosed",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_str_op(errmsg, OP_EQ, "Unrecognized handshake type");
+ errmsg = NULL;
+
+ done:
+ UNMOCK(rep_hist_get_circuit_handshake_requested);
+ UNMOCK(rep_hist_get_circuit_handshake_assigned);
+ tor_free(answer);
+
+ return;
+}
+
+#ifndef COCCI
+#define PARSER_TEST(type) \
+ { "parse/" #type, test_controller_parse_cmd, 0, &passthrough_setup, \
+ (void*)&parse_ ## type ## _params }
+#endif
+
struct testcase_t controller_tests[] = {
+ PARSER_TEST(one_to_three),
+ PARSER_TEST(no_args_one_obj),
+ PARSER_TEST(no_args_kwargs),
+ PARSER_TEST(one_arg_kwargs),
{ "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0,
NULL, NULL },
{ "add_onion_helper_keyarg_v3", test_add_onion_helper_keyarg_v3, 0,
@@ -1626,11 +2220,18 @@ struct testcase_t controller_tests[] = {
NULL },
{ "download_status_consensus", test_download_status_consensus, 0, NULL,
NULL },
+ {"getinfo_helper_current_consensus_from_cache",
+ test_getinfo_helper_current_consensus_from_cache, 0, NULL, NULL },
+ {"getinfo_helper_current_consensus_from_file",
+ test_getinfo_helper_current_consensus_from_file, 0, NULL, NULL },
{ "download_status_cert", test_download_status_cert, 0, NULL,
NULL },
{ "download_status_desc", test_download_status_desc, 0, NULL, NULL },
{ "download_status_bridge", test_download_status_bridge, 0, NULL, NULL },
{ "current_time", test_current_time, 0, NULL, NULL },
{ "getinfo_md_all", test_getinfo_md_all, 0, NULL, NULL },
+ { "control_reply", test_control_reply, 0, NULL, NULL },
+ { "control_getconf", test_control_getconf, 0, NULL, NULL },
+ { "stats", test_stats, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c
index 70d36e53d4..3cd529fa10 100644
--- a/src/test/test_controller_events.c
+++ b/src/test/test_controller_events.c
@@ -1,19 +1,30 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CONTROL_PRIVATE
+#define CONTROL_EVENTS_PRIVATE
+#define OCIRC_EVENT_PRIVATE
+#define ORCONN_EVENT_PRIVATE
+#include "app/main/subsysmgr.h"
#include "core/or/or.h"
#include "core/or/channel.h"
#include "core/or/channeltls.h"
#include "core/or/circuitlist.h"
+#include "core/or/ocirc_event.h"
+#include "core/or/orconn_event.h"
#include "core/mainloop/connection.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
+#include "feature/control/control_fmt.h"
#include "test/test.h"
+#include "test/test_helpers.h"
+#include "test/log_test_helpers.h"
+#include "core/or/entry_connection_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
+#include "core/or/socks_request_st.h"
static void
add_testing_cell_stats_entry(circuit_t *circ, uint8_t command,
@@ -351,10 +362,10 @@ test_cntev_dirboot_defer_desc(void *arg)
/* This event should get deferred */
control_event_boot_dir(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
assert_bootmsg("0 TAG=starting");
- control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0);
- assert_bootmsg("5 TAG=conn_dir");
+ control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0);
+ assert_bootmsg("5 TAG=conn");
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
- assert_bootmsg("10 TAG=handshake_dir");
+ assert_bootmsg("14 TAG=handshake");
/* The deferred event should appear */
control_event_boot_first_orconn();
assert_bootmsg("45 TAG=requesting_descriptors");
@@ -374,29 +385,371 @@ test_cntev_dirboot_defer_orconn(void *arg)
control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0);
assert_bootmsg("0 TAG=starting");
/* This event should get deferred */
- control_event_boot_dir(BOOTSTRAP_STATUS_CONN_OR, 0);
+ control_event_boot_dir(BOOTSTRAP_STATUS_ENOUGH_DIRINFO, 0);
assert_bootmsg("0 TAG=starting");
- control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0);
- assert_bootmsg("5 TAG=conn_dir");
+ control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0);
+ assert_bootmsg("5 TAG=conn");
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
- assert_bootmsg("10 TAG=handshake_dir");
+ assert_bootmsg("14 TAG=handshake");
/* The deferred event should appear */
control_event_boot_first_orconn();
- assert_bootmsg("80 TAG=conn_or");
+ assert_bootmsg("75 TAG=enough_dirinfo");
done:
tor_free(saved_event_str);
UNMOCK(queue_control_event_string);
}
-#define TEST(name, flags) \
+static void
+test_cntev_signal(void *arg)
+{
+ (void)arg;
+ int rv;
+
+ MOCK(queue_control_event_string, mock_queue_control_event_string);
+
+ /* Nothing is listening for signals, so no event should be queued. */
+ rv = control_event_signal(SIGHUP);
+ tt_int_op(0, OP_EQ, rv);
+ tt_ptr_op(saved_event_str, OP_EQ, NULL);
+
+ /* Now try with signals included in the event mask. */
+ control_testing_set_global_event_mask(EVENT_MASK_(EVENT_GOT_SIGNAL));
+ rv = control_event_signal(SIGHUP);
+ tt_int_op(0, OP_EQ, rv);
+ tt_str_op(saved_event_str, OP_EQ, "650 SIGNAL RELOAD\r\n");
+
+ rv = control_event_signal(SIGACTIVE);
+ tt_int_op(0, OP_EQ, rv);
+ tt_str_op(saved_event_str, OP_EQ, "650 SIGNAL ACTIVE\r\n");
+
+ /* Try a signal that doesn't exist. */
+ setup_full_capture_of_logs(LOG_WARN);
+ tor_free(saved_event_str);
+ rv = control_event_signal(99999);
+ tt_int_op(-1, OP_EQ, rv);
+ tt_ptr_op(saved_event_str, OP_EQ, NULL);
+ expect_single_log_msg_containing("Unrecognized signal 99999");
+
+ done:
+ tor_free(saved_event_str);
+ teardown_capture_of_logs();
+ UNMOCK(queue_control_event_string);
+}
+
+static void
+test_cntev_log_fmt(void *arg)
+{
+ (void) arg;
+ char *result = NULL;
+#define CHECK(pre, post) \
+ do { \
+ result = tor_strdup((pre)); \
+ control_logmsg_strip_newlines(result); \
+ tt_str_op(result, OP_EQ, (post)); \
+ tor_free(result); \
+ } while (0)
+
+ CHECK("There is a ", "There is a");
+ CHECK("hello", "hello");
+ CHECK("", "");
+ CHECK("Put spaces at the end ", "Put spaces at the end");
+ CHECK(" ", "");
+ CHECK("\n\n\n", "");
+ CHECK("Testing\r\n", "Testing");
+ CHECK("T e s t\ni n g\n", "T e s t i n g");
+
+ done:
+ tor_free(result);
+#undef CHECK
+}
+
+static void
+setup_orconn_state(orconn_state_msg_t *msg, uint64_t gid, uint64_t chan,
+ int proxy_type)
+{
+ msg->gid = gid;
+ msg->chan = chan;
+ msg->proxy_type = proxy_type;
+}
+
+static void
+send_orconn_state(const orconn_state_msg_t *msg_in, uint8_t state)
+{
+ orconn_state_msg_t *msg = tor_malloc(sizeof(*msg));
+
+ *msg = *msg_in;
+ msg->state = state;
+ orconn_state_publish(msg);
+}
+
+static void
+send_ocirc_chan(uint32_t gid, uint64_t chan, bool onehop)
+{
+ ocirc_chan_msg_t *msg = tor_malloc(sizeof(*msg));
+
+ msg->gid = gid;
+ msg->chan = chan;
+ msg->onehop = onehop;
+ ocirc_chan_publish(msg);
+}
+
+static void
+test_cntev_orconn_state(void *arg)
+{
+ orconn_state_msg_t conn;
+ memset(&conn, 0, sizeof(conn));
+
+ (void)arg;
+ MOCK(queue_control_event_string, mock_queue_control_event_string);
+ control_testing_set_global_event_mask(EVENT_MASK_(EVENT_STATUS_CLIENT));
+ setup_orconn_state(&conn, 1, 1, PROXY_NONE);
+
+ send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
+ send_ocirc_chan(1, 1, true);
+ assert_bootmsg("5 TAG=conn");
+ send_orconn_state(&conn, OR_CONN_STATE_TLS_HANDSHAKING);
+ assert_bootmsg("10 TAG=conn_done");
+ send_orconn_state(&conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
+ assert_bootmsg("14 TAG=handshake");
+ send_orconn_state(&conn, OR_CONN_STATE_OPEN);
+ assert_bootmsg("15 TAG=handshake_done");
+
+ conn.gid = 2;
+ conn.chan = 2;
+ send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
+ /* It doesn't know it's an origin circuit yet */
+ assert_bootmsg("15 TAG=handshake_done");
+ send_ocirc_chan(2, 2, false);
+ assert_bootmsg("80 TAG=ap_conn");
+ send_orconn_state(&conn, OR_CONN_STATE_TLS_HANDSHAKING);
+ assert_bootmsg("85 TAG=ap_conn_done");
+ send_orconn_state(&conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
+ assert_bootmsg("89 TAG=ap_handshake");
+ send_orconn_state(&conn, OR_CONN_STATE_OPEN);
+ assert_bootmsg("90 TAG=ap_handshake_done");
+
+ done:
+ tor_free(saved_event_str);
+ UNMOCK(queue_control_event_string);
+}
+
+static void
+test_cntev_orconn_state_pt(void *arg)
+{
+ orconn_state_msg_t conn;
+ memset(&conn, 0, sizeof(conn));
+
+ (void)arg;
+ MOCK(queue_control_event_string, mock_queue_control_event_string);
+ control_testing_set_global_event_mask(EVENT_MASK_(EVENT_STATUS_CLIENT));
+ setup_orconn_state(&conn, 1, 1, PROXY_PLUGGABLE);
+ send_ocirc_chan(1, 1, true);
+
+ send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
+ assert_bootmsg("1 TAG=conn_pt");
+ send_orconn_state(&conn, OR_CONN_STATE_PROXY_HANDSHAKING);
+ assert_bootmsg("2 TAG=conn_done_pt");
+ send_orconn_state(&conn, OR_CONN_STATE_TLS_HANDSHAKING);
+ assert_bootmsg("10 TAG=conn_done");
+ send_orconn_state(&conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
+ assert_bootmsg("14 TAG=handshake");
+ send_orconn_state(&conn, OR_CONN_STATE_OPEN);
+ assert_bootmsg("15 TAG=handshake_done");
+
+ send_ocirc_chan(2, 2, false);
+ conn.gid = 2;
+ conn.chan = 2;
+ send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
+ assert_bootmsg("76 TAG=ap_conn_pt");
+ send_orconn_state(&conn, OR_CONN_STATE_PROXY_HANDSHAKING);
+ assert_bootmsg("77 TAG=ap_conn_done_pt");
+
+ done:
+ tor_free(saved_event_str);
+ UNMOCK(queue_control_event_string);
+}
+
+static void
+test_cntev_orconn_state_proxy(void *arg)
+{
+ orconn_state_msg_t conn;
+ memset(&conn, 0, sizeof(conn));
+
+ (void)arg;
+ MOCK(queue_control_event_string, mock_queue_control_event_string);
+ control_testing_set_global_event_mask(EVENT_MASK_(EVENT_STATUS_CLIENT));
+ setup_orconn_state(&conn, 1, 1, PROXY_CONNECT);
+ send_ocirc_chan(1, 1, true);
+
+ send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
+ assert_bootmsg("3 TAG=conn_proxy");
+ send_orconn_state(&conn, OR_CONN_STATE_PROXY_HANDSHAKING);
+ assert_bootmsg("4 TAG=conn_done_proxy");
+ send_orconn_state(&conn, OR_CONN_STATE_TLS_HANDSHAKING);
+ assert_bootmsg("10 TAG=conn_done");
+ send_orconn_state(&conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
+ assert_bootmsg("14 TAG=handshake");
+ send_orconn_state(&conn, OR_CONN_STATE_OPEN);
+ assert_bootmsg("15 TAG=handshake_done");
+
+ send_ocirc_chan(2, 2, false);
+ conn.gid = 2;
+ conn.chan = 2;
+ send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
+ assert_bootmsg("78 TAG=ap_conn_proxy");
+ send_orconn_state(&conn, OR_CONN_STATE_PROXY_HANDSHAKING);
+ assert_bootmsg("79 TAG=ap_conn_done_proxy");
+
+ done:
+ tor_free(saved_event_str);
+ UNMOCK(queue_control_event_string);
+}
+
+static void
+test_cntev_format_stream(void *arg)
+{
+ entry_connection_t *ec = NULL;
+ char *conndesc = NULL;
+ (void)arg;
+
+ ec = entry_connection_new(CONN_TYPE_AP, AF_INET);
+
+ char *username = tor_strdup("jeremy");
+ char *password = tor_strdup("letmein");
+ ec->socks_request->username = username; // steal reference
+ ec->socks_request->usernamelen = strlen(username);
+ ec->socks_request->password = password; // steal reference
+ ec->socks_request->passwordlen = strlen(password);
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "SOCKS_USERNAME=\"jeremy\""));
+ tt_assert(strstr(conndesc, "SOCKS_PASSWORD=\"letmein\""));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_LISTENER;
+ ec->socks_request->socks_version = 4;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=SOCKS4"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_LISTENER;
+ ec->socks_request->socks_version = 5;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=SOCKS5"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_LISTENER;
+ ec->socks_request->socks_version = 6;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=UNKNOWN"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_TRANS_LISTENER;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=TRANS"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_NATD_LISTENER;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=NATD"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_DNS_LISTENER;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=DNS"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_AP_HTTP_CONNECT_LISTENER;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=HTTPCONNECT"));
+ tor_free(conndesc);
+
+ ec->socks_request->listener_type = CONN_TYPE_OR;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "CLIENT_PROTOCOL=UNKNOWN"));
+ tor_free(conndesc);
+
+ ec->nym_epoch = 1337;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "NYM_EPOCH=1337"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.session_group = 4321;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "SESSION_GROUP=4321"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_DESTPORT;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=DESTPORT"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=DESTPORT,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_DESTADDR;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=DESTADDR"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=DESTADDR,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_SOCKSAUTH;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=SOCKS_USERNAME,SOCKS_PASSWORD"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=SOCKS_USERNAME,SOCKS_PASSWORD,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_CLIENTPROTO;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=CLIENT_PROTOCOL"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=CLIENT_PROTOCOL,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_CLIENTADDR;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=CLIENTADDR"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=CLIENTADDR,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_SESSIONGRP;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=SESSION_GROUP"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=SESSION_GROUP,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_NYM_EPOCH;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc, "ISO_FIELDS=NYM_EPOCH"));
+ tt_assert(!strstr(conndesc, "ISO_FIELDS=NYM_EPOCH,"));
+ tor_free(conndesc);
+
+ ec->entry_cfg.isolation_flags = ISO_DESTPORT | ISO_SOCKSAUTH | ISO_NYM_EPOCH;
+ conndesc = entry_connection_describe_status_for_controller(ec);
+ tt_assert(strstr(conndesc,
+ "ISO_FIELDS=DESTPORT,SOCKS_USERNAME,SOCKS_PASSWORD,NYM_EPOCH"));
+ tt_assert(!strstr(conndesc,
+ "ISO_FIELDS=DESTPORT,SOCKS_USERNAME,SOCKS_PASSWORD,NYM_EPOCH,"));
+
+ done:
+ tor_free(conndesc);
+ connection_free_minimal(ENTRY_TO_CONN(ec));
+}
+
+#define TEST(name, flags) \
{ #name, test_cntev_ ## name, flags, 0, NULL }
+#define T_PUBSUB(name, setup) \
+ { #name, test_cntev_ ## name, TT_FORK, &helper_pubsub_setup, NULL }
+
struct testcase_t controller_event_tests[] = {
TEST(sum_up_cell_stats, TT_FORK),
TEST(append_cell_stats, TT_FORK),
TEST(format_cell_stats, TT_FORK),
TEST(event_mask, TT_FORK),
- TEST(dirboot_defer_desc, TT_FORK),
- TEST(dirboot_defer_orconn, TT_FORK),
+ TEST(format_stream, TT_FORK),
+ TEST(signal, TT_FORK),
+ TEST(log_fmt, 0),
+ T_PUBSUB(dirboot_defer_desc, TT_FORK),
+ T_PUBSUB(dirboot_defer_orconn, TT_FORK),
+ T_PUBSUB(orconn_state, TT_FORK),
+ T_PUBSUB(orconn_state_pt, TT_FORK),
+ T_PUBSUB(orconn_state_proxy, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 5af0cce130..ffd6a25bd5 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -29,10 +29,10 @@
#if defined(ENABLE_OPENSSL)
#include "lib/crypt_ops/compat_openssl.h"
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/dh.h>
-ENABLE_GCC_WARNING(redundant-decls)
-#endif
+ENABLE_GCC_WARNING("-Wredundant-decls")
+#endif /* defined(ENABLE_OPENSSL) */
/** Run unit tests for Diffie-Hellman functionality. */
static void
@@ -190,7 +190,7 @@ test_crypto_dh(void *arg)
DH_get0_key(dh4, &pk, &sk);
#else
pk = dh4->pub_key;
-#endif
+#endif /* defined(OPENSSL_1_1_API) */
tt_assert(pk);
tt_int_op(BN_num_bytes(pk), OP_LE, DH1024_KEY_LEN);
tt_int_op(BN_num_bytes(pk), OP_GT, 0);
@@ -207,7 +207,7 @@ test_crypto_dh(void *arg)
tt_int_op(s1len, OP_GT, 0);
tt_mem_op(s1, OP_EQ, s2, s1len);
}
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
done:
crypto_dh_free(dh1);
@@ -219,7 +219,7 @@ test_crypto_dh(void *arg)
DH_free(dh4);
if (pubkey_tmp)
BN_free(pubkey_tmp);
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
}
static void
@@ -248,174 +248,12 @@ test_crypto_openssl_version(void *arg)
tt_int_op(a, OP_GE, 0);
tt_int_op(b, OP_GE, 0);
tt_int_op(c, OP_GE, 0);
-#endif
+#endif /* defined(ENABLE_NSS) */
done:
;
}
-/** Run unit tests for our random number generation function and its wrappers.
- */
-static void
-test_crypto_rng(void *arg)
-{
- int i, j, allok;
- char data1[100], data2[100];
- double d;
- char *h=NULL;
-
- /* Try out RNG. */
- (void)arg;
- tt_assert(! crypto_seed_rng());
- crypto_rand(data1, 100);
- crypto_rand(data2, 100);
- tt_mem_op(data1,OP_NE, data2,100);
- allok = 1;
- for (i = 0; i < 100; ++i) {
- uint64_t big;
- char *host;
- j = crypto_rand_int(100);
- if (j < 0 || j >= 100)
- allok = 0;
- big = crypto_rand_uint64(UINT64_C(1)<<40);
- if (big >= (UINT64_C(1)<<40))
- allok = 0;
- big = crypto_rand_uint64(UINT64_C(5));
- if (big >= 5)
- allok = 0;
- d = crypto_rand_double();
- tt_assert(d >= 0);
- tt_assert(d < 1.0);
- host = crypto_random_hostname(3,8,"www.",".onion");
- if (strcmpstart(host,"www.") ||
- strcmpend(host,".onion") ||
- strlen(host) < 13 ||
- strlen(host) > 18)
- allok = 0;
- tor_free(host);
- }
-
- /* Make sure crypto_random_hostname clips its inputs properly. */
- h = crypto_random_hostname(20000, 9000, "www.", ".onion");
- tt_assert(! strcmpstart(h,"www."));
- tt_assert(! strcmpend(h,".onion"));
- tt_int_op(63+4+6, OP_EQ, strlen(h));
-
- tt_assert(allok);
- done:
- tor_free(h);
-}
-
-static void
-test_crypto_rng_range(void *arg)
-{
- int got_smallest = 0, got_largest = 0;
- int i;
-
- (void)arg;
- for (i = 0; i < 1000; ++i) {
- int x = crypto_rand_int_range(5,9);
- tt_int_op(x, OP_GE, 5);
- tt_int_op(x, OP_LT, 9);
- if (x == 5)
- got_smallest = 1;
- if (x == 8)
- got_largest = 1;
- }
- /* These fail with probability 1/10^603. */
- tt_assert(got_smallest);
- tt_assert(got_largest);
-
- got_smallest = got_largest = 0;
- const uint64_t ten_billion = 10 * ((uint64_t)1000000000000);
- for (i = 0; i < 1000; ++i) {
- uint64_t x = crypto_rand_uint64_range(ten_billion, ten_billion+10);
- tt_u64_op(x, OP_GE, ten_billion);
- tt_u64_op(x, OP_LT, ten_billion+10);
- if (x == ten_billion)
- got_smallest = 1;
- if (x == ten_billion+9)
- got_largest = 1;
- }
-
- tt_assert(got_smallest);
- tt_assert(got_largest);
-
- const time_t now = time(NULL);
- for (i = 0; i < 2000; ++i) {
- time_t x = crypto_rand_time_range(now, now+60);
- tt_i64_op(x, OP_GE, now);
- tt_i64_op(x, OP_LT, now+60);
- if (x == now)
- got_smallest = 1;
- if (x == now+59)
- got_largest = 1;
- }
-
- tt_assert(got_smallest);
- tt_assert(got_largest);
- done:
- ;
-}
-
-static void
-test_crypto_rng_strongest(void *arg)
-{
- const char *how = arg;
- int broken = 0;
-
- if (how == NULL) {
- ;
- } else if (!strcmp(how, "nosyscall")) {
- break_strongest_rng_syscall = 1;
- } else if (!strcmp(how, "nofallback")) {
- break_strongest_rng_fallback = 1;
- } else if (!strcmp(how, "broken")) {
- broken = break_strongest_rng_syscall = break_strongest_rng_fallback = 1;
- }
-
-#define N 128
- uint8_t combine_and[N];
- uint8_t combine_or[N];
- int i, j;
-
- memset(combine_and, 0xff, N);
- memset(combine_or, 0, N);
-
- for (i = 0; i < 100; ++i) { /* 2^-100 chances just don't happen. */
- uint8_t output[N];
- memset(output, 0, N);
- if (how == NULL) {
- /* this one can't fail. */
- crypto_strongest_rand(output, sizeof(output));
- } else {
- int r = crypto_strongest_rand_raw(output, sizeof(output));
- if (r == -1) {
- if (broken) {
- goto done; /* we're fine. */
- }
- /* This function is allowed to break, but only if it always breaks. */
- tt_int_op(i, OP_EQ, 0);
- tt_skip();
- } else {
- tt_assert(! broken);
- }
- }
- for (j = 0; j < N; ++j) {
- combine_and[j] &= output[j];
- combine_or[j] |= output[j];
- }
- }
-
- for (j = 0; j < N; ++j) {
- tt_int_op(combine_and[j], OP_EQ, 0);
- tt_int_op(combine_or[j], OP_EQ, 0xff);
- }
- done:
- ;
-#undef N
-}
-
/** Run unit tests for our AES128 functionality */
static void
test_crypto_aes128(void *arg)
@@ -551,7 +389,7 @@ test_crypto_aes128(void *arg)
"\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff");
crypto_cipher_crypt_inplace(env1, data2, 64);
- tt_assert(tor_mem_is_zero(data2, 64));
+ tt_assert(fast_mem_is_zero(data2, 64));
done:
tor_free(mem_op_hex_tmp);
@@ -1173,13 +1011,19 @@ test_crypto_sha3_xof(void *arg)
crypto_xof_free(xof);
memset(out, 0, sizeof(out));
+ /* Test one-function absorb/squeeze. */
+ crypto_xof(out, sizeof(out), msg, sizeof(msg));
+ test_memeq_hex(out, squeezed_hex);
+ memset(out, 0, sizeof(out));
+
/* Test incremental absorb/squeeze. */
xof = crypto_xof_new();
tt_assert(xof);
for (size_t i = 0; i < sizeof(msg); i++)
crypto_xof_add_bytes(xof, msg + i, 1);
- for (size_t i = 0; i < sizeof(out); i++)
+ for (size_t i = 0; i < sizeof(out); i++) {
crypto_xof_squeeze_bytes(xof, out + i, 1);
+ }
test_memeq_hex(out, squeezed_hex);
done:
@@ -1903,13 +1747,13 @@ test_crypto_base32_decode(void *arg)
/* Encode and decode a random string. */
base32_encode(encoded, 96 + 1, plain, 60);
res = base32_decode(decoded, 60, encoded, 96);
- tt_int_op(res,OP_EQ, 0);
+ tt_int_op(res, OP_EQ, 60);
tt_mem_op(plain,OP_EQ, decoded, 60);
/* Encode, uppercase, and decode a random string. */
base32_encode(encoded, 96 + 1, plain, 60);
tor_strupper(encoded);
res = base32_decode(decoded, 60, encoded, 96);
- tt_int_op(res,OP_EQ, 0);
+ tt_int_op(res, OP_EQ, 60);
tt_mem_op(plain,OP_EQ, decoded, 60);
/* Change encoded string and decode. */
if (encoded[0] == 'A' || encoded[0] == 'a')
@@ -1917,12 +1761,12 @@ test_crypto_base32_decode(void *arg)
else
encoded[0] = 'A';
res = base32_decode(decoded, 60, encoded, 96);
- tt_int_op(res,OP_EQ, 0);
+ tt_int_op(res, OP_EQ, 60);
tt_mem_op(plain,OP_NE, decoded, 60);
/* Bad encodings. */
encoded[0] = '!';
res = base32_decode(decoded, 60, encoded, 96);
- tt_int_op(0, OP_GT, res);
+ tt_int_op(res, OP_LT, 0);
done:
;
@@ -2117,7 +1961,7 @@ test_crypto_curve25519_impl(void *arg)
"e0544770bc7de853b38f9100489e3e79";
const char e1e2k_expected[] = "cd6e8269104eb5aaee886bd2071fba88"
"bd13861475516bc2cd2b6e005e805064";
-#else /* !(defined(SLOW_CURVE25519_TEST)) */
+#else /* !defined(SLOW_CURVE25519_TEST) */
const int loop_max=200;
const char e1_expected[] = "bc7112cde03f97ef7008cad1bdc56be3"
"c6a1037d74cceb3712e9206871dcf654";
@@ -2263,21 +2107,21 @@ test_crypto_curve25519_encode(void *arg)
{
curve25519_secret_key_t seckey;
curve25519_public_key_t key1, key2, key3;
- char buf[64];
+ char buf[64], buf_nopad[64];
(void)arg;
curve25519_secret_key_generate(&seckey, 0);
curve25519_public_key_generate(&key1, &seckey);
- tt_int_op(0, OP_EQ, curve25519_public_to_base64(buf, &key1));
+ curve25519_public_to_base64(buf, &key1, true);
tt_int_op(CURVE25519_BASE64_PADDED_LEN, OP_EQ, strlen(buf));
tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key2, buf));
tt_mem_op(key1.public_key,OP_EQ, key2.public_key, CURVE25519_PUBKEY_LEN);
- buf[CURVE25519_BASE64_PADDED_LEN - 1] = '\0';
- tt_int_op(CURVE25519_BASE64_PADDED_LEN-1, OP_EQ, strlen(buf));
- tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key3, buf));
+ curve25519_public_to_base64(buf_nopad, &key1, false);
+ tt_int_op(CURVE25519_BASE64_LEN, OP_EQ, strlen(buf_nopad));
+ tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key3, buf_nopad));
tt_mem_op(key1.public_key,OP_EQ, key3.public_key, CURVE25519_PUBKEY_LEN);
/* Now try bogus parses. */
@@ -2328,7 +2172,7 @@ test_crypto_curve25519_persist(void *arg)
tt_u64_op((uint64_t)st.st_size, OP_EQ,
32+CURVE25519_PUBKEY_LEN+CURVE25519_SECKEY_LEN);
tt_assert(fast_memeq(content, "== c25519v1: testing ==", taglen));
- tt_assert(tor_mem_is_zero(content+taglen, 32-taglen));
+ tt_assert(fast_mem_is_zero(content+taglen, 32-taglen));
cp = content + 32;
tt_mem_op(keypair.seckey.secret_key,OP_EQ,
cp,
@@ -2649,13 +2493,13 @@ test_crypto_ed25519_encode(void *arg)
/* Test roundtrip. */
tt_int_op(0, OP_EQ, ed25519_keypair_generate(&kp, 0));
- tt_int_op(0, OP_EQ, ed25519_public_to_base64(buf, &kp.pubkey));
+ ed25519_public_to_base64(buf, &kp.pubkey);
tt_int_op(ED25519_BASE64_LEN, OP_EQ, strlen(buf));
tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk, buf));
tt_mem_op(kp.pubkey.pubkey, OP_EQ, pk.pubkey, ED25519_PUBKEY_LEN);
tt_int_op(0, OP_EQ, ed25519_sign(&sig1, (const uint8_t*)"ABC", 3, &kp));
- tt_int_op(0, OP_EQ, ed25519_signature_to_base64(buf, &sig1));
+ ed25519_signature_to_base64(buf, &sig1);
tt_int_op(0, OP_EQ, ed25519_signature_from_base64(&sig2, buf));
tt_mem_op(sig1.sig, OP_EQ, sig2.sig, ED25519_SIG_LEN);
@@ -3165,6 +3009,7 @@ test_crypto_failure_modes(void *arg)
;
}
+#ifndef COCCI
#define CRYPTO_LEGACY(name) \
{ #name, test_crypto_ ## name , 0, NULL, NULL }
@@ -3175,18 +3020,10 @@ test_crypto_failure_modes(void *arg)
#define ED25519_TEST(name, fl) \
ED25519_TEST_ONE(name, (fl), "donna"), \
ED25519_TEST_ONE(name, (fl), "ref10")
+#endif /* !defined(COCCI) */
struct testcase_t crypto_tests[] = {
CRYPTO_LEGACY(formats),
- CRYPTO_LEGACY(rng),
- { "rng_range", test_crypto_rng_range, 0, NULL, NULL },
- { "rng_strongest", test_crypto_rng_strongest, TT_FORK, NULL, NULL },
- { "rng_strongest_nosyscall", test_crypto_rng_strongest, TT_FORK,
- &passthrough_setup, (void*)"nosyscall" },
- { "rng_strongest_nofallback", test_crypto_rng_strongest, TT_FORK,
- &passthrough_setup, (void*)"nofallback" },
- { "rng_strongest_broken", test_crypto_rng_strongest, TT_FORK,
- &passthrough_setup, (void*)"broken" },
{ "openssl_version", test_crypto_openssl_version, TT_FORK, NULL, NULL },
{ "aes_AES", test_crypto_aes128, TT_FORK, &passthrough_setup, (void*)"aes" },
{ "aes_EVP", test_crypto_aes128, TT_FORK, &passthrough_setup, (void*)"evp" },
diff --git a/src/test/test_crypto_ope.c b/src/test/test_crypto_ope.c
index dc67c02676..119ebc114a 100644
--- a/src/test/test_crypto_ope.c
+++ b/src/test/test_crypto_ope.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_crypto_openssl.c b/src/test/test_crypto_openssl.c
index 42dc3f6be2..989f4a56ca 100644
--- a/src/test/test_crypto_openssl.c
+++ b/src/test/test_crypto_openssl.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_crypto_rng.c b/src/test/test_crypto_rng.c
new file mode 100644
index 0000000000..b0dc4c117c
--- /dev/null
+++ b/src/test/test_crypto_rng.c
@@ -0,0 +1,332 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#define CRYPTO_RAND_PRIVATE
+#include "core/or/or.h"
+#include "test/test.h"
+#include "lib/crypt_ops/aes.h"
+#include "lib/crypt_ops/crypto_format.h"
+#include "lib/crypt_ops/crypto_rand.h"
+
+/** Run unit tests for our random number generation function and its wrappers.
+ */
+static void
+test_crypto_rng(void *arg)
+{
+ int i, j, allok;
+ char data1[100], data2[100];
+ double d;
+ char *h=NULL;
+
+ /* Try out RNG. */
+ (void)arg;
+ tt_assert(! crypto_seed_rng());
+ crypto_rand(data1, 100);
+ crypto_rand(data2, 100);
+ tt_mem_op(data1,OP_NE, data2,100);
+ allok = 1;
+ for (i = 0; i < 100; ++i) {
+ uint64_t big;
+ char *host;
+ j = crypto_rand_int(100);
+ if (j < 0 || j >= 100)
+ allok = 0;
+ big = crypto_rand_uint64(UINT64_C(1)<<40);
+ if (big >= (UINT64_C(1)<<40))
+ allok = 0;
+ big = crypto_rand_uint64(UINT64_C(5));
+ if (big >= 5)
+ allok = 0;
+ d = crypto_rand_double();
+ tt_assert(d >= 0);
+ tt_assert(d < 1.0);
+ host = crypto_random_hostname(3,8,"www.",".onion");
+ if (strcmpstart(host,"www.") ||
+ strcmpend(host,".onion") ||
+ strlen(host) < 13 ||
+ strlen(host) > 18)
+ allok = 0;
+ tor_free(host);
+ }
+
+ /* Make sure crypto_random_hostname clips its inputs properly. */
+ h = crypto_random_hostname(20000, 9000, "www.", ".onion");
+ tt_assert(! strcmpstart(h,"www."));
+ tt_assert(! strcmpend(h,".onion"));
+ tt_int_op(63+4+6, OP_EQ, strlen(h));
+
+ tt_assert(allok);
+ done:
+ tor_free(h);
+}
+
+static void
+test_crypto_rng_range(void *arg)
+{
+ int got_smallest = 0, got_largest = 0;
+ int i;
+
+ (void)arg;
+ for (i = 0; i < 1000; ++i) {
+ int x = crypto_rand_int_range(5,9);
+ tt_int_op(x, OP_GE, 5);
+ tt_int_op(x, OP_LT, 9);
+ if (x == 5)
+ got_smallest = 1;
+ if (x == 8)
+ got_largest = 1;
+ }
+ /* These fail with probability 1/10^603. */
+ tt_assert(got_smallest);
+ tt_assert(got_largest);
+
+ got_smallest = got_largest = 0;
+ const uint64_t ten_billion = 10 * ((uint64_t)1000000000000);
+ for (i = 0; i < 1000; ++i) {
+ uint64_t x = crypto_rand_uint64_range(ten_billion, ten_billion+10);
+ tt_u64_op(x, OP_GE, ten_billion);
+ tt_u64_op(x, OP_LT, ten_billion+10);
+ if (x == ten_billion)
+ got_smallest = 1;
+ if (x == ten_billion+9)
+ got_largest = 1;
+ }
+
+ tt_assert(got_smallest);
+ tt_assert(got_largest);
+
+ const time_t now = time(NULL);
+ for (i = 0; i < 2000; ++i) {
+ time_t x = crypto_rand_time_range(now, now+60);
+ tt_i64_op(x, OP_GE, now);
+ tt_i64_op(x, OP_LT, now+60);
+ if (x == now)
+ got_smallest = 1;
+ if (x == now+59)
+ got_largest = 1;
+ }
+
+ tt_assert(got_smallest);
+ tt_assert(got_largest);
+ done:
+ ;
+}
+
+static void
+test_crypto_rng_strongest(void *arg)
+{
+ const char *how = arg;
+ int broken = 0;
+
+ if (how == NULL) {
+ ;
+ } else if (!strcmp(how, "nosyscall")) {
+ break_strongest_rng_syscall = 1;
+ } else if (!strcmp(how, "nofallback")) {
+ break_strongest_rng_fallback = 1;
+ } else if (!strcmp(how, "broken")) {
+ broken = break_strongest_rng_syscall = break_strongest_rng_fallback = 1;
+ }
+
+#define N 128
+ uint8_t combine_and[N];
+ uint8_t combine_or[N];
+ int i, j;
+
+ memset(combine_and, 0xff, N);
+ memset(combine_or, 0, N);
+
+ for (i = 0; i < 100; ++i) { /* 2^-100 chances just don't happen. */
+ uint8_t output[N];
+ memset(output, 0, N);
+ if (how == NULL) {
+ /* this one can't fail. */
+ crypto_strongest_rand(output, sizeof(output));
+ } else {
+ int r = crypto_strongest_rand_raw(output, sizeof(output));
+ if (r == -1) {
+ if (broken) {
+ goto done; /* we're fine. */
+ }
+ /* This function is allowed to break, but only if it always breaks. */
+ tt_int_op(i, OP_EQ, 0);
+ tt_skip();
+ } else {
+ tt_assert(! broken);
+ }
+ }
+ for (j = 0; j < N; ++j) {
+ combine_and[j] &= output[j];
+ combine_or[j] |= output[j];
+ }
+ }
+
+ for (j = 0; j < N; ++j) {
+ tt_int_op(combine_and[j], OP_EQ, 0);
+ tt_int_op(combine_or[j], OP_EQ, 0xff);
+ }
+ done:
+ ;
+#undef N
+}
+
+static void
+test_crypto_rng_fast(void *arg)
+{
+ (void)arg;
+ crypto_fast_rng_t *rng = crypto_fast_rng_new();
+ tt_assert(rng);
+
+ /* Rudimentary black-block test to make sure that our prng outputs
+ * have all bits sometimes on and all bits sometimes off. */
+ uint64_t m1 = 0, m2 = ~(uint64_t)0;
+ const int N = 128;
+
+ for (int i=0; i < N; ++i) {
+ uint64_t v;
+ crypto_fast_rng_getbytes(rng, (void*)&v, sizeof(v));
+ m1 |= v;
+ m2 &= v;
+ }
+
+ tt_u64_op(m1, OP_EQ, ~(uint64_t)0);
+ tt_u64_op(m2, OP_EQ, 0);
+
+ /* Check range functions. */
+ int counts[5];
+ memset(counts, 0, sizeof(counts));
+ for (int i=0; i < N; ++i) {
+ unsigned u = crypto_fast_rng_get_uint(rng, 5);
+ tt_int_op(u, OP_GE, 0);
+ tt_int_op(u, OP_LT, 5);
+ counts[u]++;
+
+ uint64_t u64 = crypto_fast_rng_get_uint64(rng, UINT64_C(1)<<40);
+ tt_u64_op(u64, OP_GE, 0);
+ tt_u64_op(u64, OP_LT, UINT64_C(1)<<40);
+
+ double d = crypto_fast_rng_get_double(rng);
+ tt_assert(d >= 0.0);
+ tt_assert(d < 1.0);
+ }
+
+ /* All values should have come up once. */
+ for (int i=0; i<5; ++i) {
+ tt_int_op(counts[i], OP_GT, 0);
+ }
+
+ /* per-thread rand_fast shouldn't crash or leak. */
+ crypto_fast_rng_t *t_rng = get_thread_fast_rng();
+ for (int i = 0; i < N; ++i) {
+ uint64_t u64 = crypto_fast_rng_get_uint64(t_rng, UINT64_C(1)<<40);
+ tt_u64_op(u64, OP_GE, 0);
+ tt_u64_op(u64, OP_LT, UINT64_C(1)<<40);
+ }
+
+ done:
+ crypto_fast_rng_free(rng);
+}
+
+static void
+test_crypto_rng_fast_whitebox(void *arg)
+{
+ (void)arg;
+ const size_t buflen = crypto_fast_rng_get_bytes_used_per_stream();
+ char *buf = tor_malloc_zero(buflen);
+ char *buf2 = tor_malloc_zero(buflen);
+ char *buf3 = NULL, *buf4 = NULL;
+
+ crypto_cipher_t *cipher = NULL, *cipher2 = NULL;
+ uint8_t seed[CRYPTO_FAST_RNG_SEED_LEN];
+ memset(seed, 0, sizeof(seed));
+
+ /* Start with a prng with zero key and zero IV. */
+ crypto_fast_rng_t *rng = crypto_fast_rng_new_from_seed(seed);
+ tt_assert(rng);
+
+ /* We'll use a stream cipher to keep in sync */
+ cipher = crypto_cipher_new_with_iv_and_bits(seed, seed+32, 256);
+
+ /* The first 48 bytes are used for the next seed -- let's make sure we have
+ * them.
+ */
+ memset(seed, 0, sizeof(seed));
+ crypto_cipher_crypt_inplace(cipher, (char*)seed, sizeof(seed));
+
+ /* if we get 128 bytes, they should match the bytes from the aes256-counter
+ * stream, starting at position 48.
+ */
+ crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 128);
+ memset(buf2, 0, 128);
+ crypto_cipher_crypt_inplace(cipher, buf2, 128);
+ tt_mem_op(buf, OP_EQ, buf2, 128);
+
+ /* Try that again, with an odd number of bytes. */
+ crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 199);
+ memset(buf2, 0, 199);
+ crypto_cipher_crypt_inplace(cipher, buf2, 199);
+ tt_mem_op(buf, OP_EQ, buf2, 199);
+
+ /* Make sure that refilling works as expected: skip all but the last 5 bytes
+ * of this steam. */
+ size_t skip = buflen - (199+128) - 5;
+ crypto_fast_rng_getbytes(rng, (uint8_t*)buf, skip);
+ crypto_cipher_crypt_inplace(cipher, buf2, skip);
+
+ /* Now get the next 128 bytes. The first 5 will come from this stream, and
+ * the next 5 will come from the stream keyed by the new value of 'seed'. */
+ crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 128);
+ memset(buf2, 0, 128);
+ crypto_cipher_crypt_inplace(cipher, buf2, 5);
+ crypto_cipher_free(cipher);
+ cipher = crypto_cipher_new_with_iv_and_bits(seed, seed+32, 256);
+ memset(seed, 0, sizeof(seed));
+ crypto_cipher_crypt_inplace(cipher, (char*)seed, sizeof(seed));
+ crypto_cipher_crypt_inplace(cipher, buf2+5, 128-5);
+ tt_mem_op(buf, OP_EQ, buf2, 128);
+
+ /* And check the next 7 bytes to make sure we didn't discard anything. */
+ crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 7);
+ memset(buf2, 0, 7);
+ crypto_cipher_crypt_inplace(cipher, buf2, 7);
+ tt_mem_op(buf, OP_EQ, buf2, 7);
+
+ /* Now try the optimization for long outputs. */
+ buf3 = tor_malloc(65536);
+ crypto_fast_rng_getbytes(rng, (uint8_t*)buf3, 65536);
+
+ buf4 = tor_malloc_zero(65536);
+ uint8_t seed2[CRYPTO_FAST_RNG_SEED_LEN];
+ memset(seed2, 0, sizeof(seed2));
+ crypto_cipher_crypt_inplace(cipher, (char*)seed2, sizeof(seed2));
+ cipher2 = crypto_cipher_new_with_iv_and_bits(seed2, seed2+32, 256);
+ crypto_cipher_crypt_inplace(cipher2, buf4, 65536);
+ tt_mem_op(buf3, OP_EQ, buf4, 65536);
+
+ done:
+ crypto_fast_rng_free(rng);
+ crypto_cipher_free(cipher);
+ crypto_cipher_free(cipher2);
+ tor_free(buf);
+ tor_free(buf2);
+ tor_free(buf3);
+ tor_free(buf4);
+}
+
+struct testcase_t crypto_rng_tests[] = {
+ { "rng", test_crypto_rng, 0, NULL, NULL },
+ { "rng_range", test_crypto_rng_range, 0, NULL, NULL },
+ { "rng_strongest", test_crypto_rng_strongest, TT_FORK, NULL, NULL },
+ { "rng_strongest_nosyscall", test_crypto_rng_strongest, TT_FORK,
+ &passthrough_setup, (void*)"nosyscall" },
+ { "rng_strongest_nofallback", test_crypto_rng_strongest, TT_FORK,
+ &passthrough_setup, (void*)"nofallback" },
+ { "rng_strongest_broken", test_crypto_rng_strongest, TT_FORK,
+ &passthrough_setup, (void*)"broken" },
+ { "fast", test_crypto_rng_fast, 0, NULL, NULL },
+ { "fast_whitebox", test_crypto_rng_fast_whitebox, 0, NULL, NULL },
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c
index e24aee8930..1702427b08 100644
--- a/src/test/test_crypto_slow.c
+++ b/src/test/test_crypto_slow.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -109,7 +109,7 @@ run_s2k_tests(const unsigned flags, const unsigned type,
secret_to_key_derivekey(buf3, sizeof(buf3), buf, speclen,
pw1, strlen(pw1)));
tt_mem_op(buf2, OP_EQ, buf3, sizeof(buf3));
- tt_assert(!tor_mem_is_zero((char*)buf2+keylen, sizeof(buf2)-keylen));
+ tt_assert(!fast_mem_is_zero((char*)buf2+keylen, sizeof(buf2)-keylen));
done:
;
@@ -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.
@@ -584,6 +584,7 @@ test_crypto_ed25519_fuzz_donna(void *arg)
;
}
+#ifndef COCCI
#define CRYPTO_LEGACY(name) \
{ #name, test_crypto_ ## name , 0, NULL, NULL }
@@ -594,6 +595,7 @@ test_crypto_ed25519_fuzz_donna(void *arg)
#define ED25519_TEST(name, fl) \
ED25519_TEST_ONE(name, (fl), "donna"), \
ED25519_TEST_ONE(name, (fl), "ref10")
+#endif /* !defined(COCCI) */
struct testcase_t slow_crypto_tests[] = {
CRYPTO_LEGACY(s2k_rfc2440),
diff --git a/src/test/test_data.c b/src/test/test_data.c
index fe1190ea77..30c14fcfff 100644
--- a/src/test/test_data.c
+++ b/src/test/test_data.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "test/test.h"
diff --git a/src/test/test_descriptors.inc b/src/test/test_descriptors.inc
index ecbccbd43a..445768e4bf 100644
--- a/src/test/test_descriptors.inc
+++ b/src/test/test_descriptors.inc
@@ -1,305 +1,431 @@
const char TEST_DESCRIPTORS[] =
-"@uploaded-at 2014-06-08 19:20:11\n"
-"@source \"127.0.0.1\"\n"
-"router test000a 127.0.0.1 5000 0 7000\n"
-"platform Tor 0.2.5.3-alpha-dev on Linux\n"
-"protocols Link 1 2 Circuit 1\n"
-"published 2014-06-08 19:20:11\n"
-"fingerprint C7E7 CCB8 179F 8CC3 7F5C 8A04 2B3A 180B 934B 14BA\n"
-"uptime 0\n"
-"bandwidth 1073741824 1073741824 0\n"
-"extra-info-digest 67A152A4C7686FB07664F872620635F194D76D95\n"
-"caches-extra-info\n"
-"onion-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAOuBUIEBARMkkka/TGyaQNgUEDLP0KG7sy6KNQTNOlZHUresPr/vlVjo\n"
-"HPpLMfu9M2z18c51YX/muWwY9x4MyQooD56wI4+AqXQcJRwQfQlPn3Ay82uZViA9\n"
-"DpBajRieLlKKkl145KjArpD7F5BVsqccvjErgFYXvhhjSrx7BVLnAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"signing-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAN6NLnSxWQnFXxqZi5D3b0BMgV6y9NJLGjYQVP+eWtPZWgqyv4zeYsqv\n"
-"O9y6c5lvxyUxmNHfoAbe/s8f2Vf3/YaC17asAVSln4ktrr3e9iY74a9RMWHv1Gzk\n"
-"3042nMcqj3PEhRN0PoLkcOZNjjmNbaqki6qy9bWWZDNTdo+uI44dAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"hidden-service-dir\n"
-"contact auth0@test.test\n"
-"ntor-onion-key pK4bs08ERYN591jj7ca17Rn9Q02TIEfhnjR6hSq+fhU=\n"
-"reject *:*\n"
-"router-signature\n"
-"-----BEGIN SIGNATURE-----\n"
-"rx88DuM3Y7tODlHNDDEVzKpwh3csaG1or+T4l2Xs1oq3iHHyPEtB6QTLYrC60trG\n"
-"aAPsj3DEowGfjga1b248g2dtic8Ab+0exfjMm1RHXfDam5TXXZU3A0wMyoHjqHuf\n"
-"eChGPgFNUvEc+5YtD27qEDcUjcinYztTs7/dzxBT4PE=\n"
-"-----END SIGNATURE-----\n"
-"@uploaded-at 2014-06-08 19:20:11\n"
-"@source \"127.0.0.1\"\n"
-"router test001a 127.0.0.1 5001 0 7001\n"
-"platform Tor 0.2.5.3-alpha-dev on Linux\n"
-"protocols Link 1 2 Circuit 1\n"
-"published 2014-06-08 19:20:11\n"
-"fingerprint 35DA 711C FC62 F88B C243 DE32 DC0B C28A 3F62 2610\n"
-"uptime 0\n"
-"bandwidth 1073741824 1073741824 0\n"
-"extra-info-digest 9E12278D6CF7608071FE98CE9DCEE48FA264518A\n"
-"caches-extra-info\n"
-"onion-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAPbyUrorqoXMW4oezqd307ZGxgobqvQs2nb3TdQyWrwsHtJmS3utdrJS\n"
-"xJUZPNHOQ2hrDWW1VvevYqRTGeXGZr9TDZ3+t/gVUttqYRhuzzgEKVAZSsTo5ctO\n"
-"QNHnzJ6Xx/w/trhWqPTeJ7R0TCyAbWW7aE3KaKdwvZilRZp/oRUnAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"signing-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBALwOJ7XZHBnjJEuwF3Os6eashNbTH9YnH8TBZBdKgu3iFJYqDslcMIPX\n"
-"gWCJ9apPHyh1+/8OLRWeEYlwoZzgGi0rjm/+BNeOOmJbjfyjk97DuB9/2O5zr1BM\n"
-"CvOHqQSzMD+vz1ebvfM039a2mO8lXruUFPZQaFVxk8371XP2khqhAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"hidden-service-dir\n"
-"contact auth1@test.test\n"
-"ntor-onion-key t5bI1ksTdigOksMKRHUDwx/34ajEvDN1IpArOxIEWgk=\n"
-"reject *:*\n"
-"router-signature\n"
-"-----BEGIN SIGNATURE-----\n"
-"KtMW7A/pzu+np6aKJSy6d7drIb4yjz8SPCo+oQNxj2IqNHJir2O2nWu69xy+K0c1\n"
-"RL05KkcDaYzr5hC80FD1H+sTpGYD28SPkQkzPw+0pReSDl93pVXh0rU6Cdcm75FC\n"
-"t0UZzDt4TsMuFB0ZYpM3phKcQPpiDG6aR0LskL/YUvY=\n"
-"-----END SIGNATURE-----\n"
-"@uploaded-at 2014-06-08 19:20:11\n"
-"@source \"127.0.0.1\"\n"
-"router test004r 127.0.0.1 5004 0 7004\n"
-"platform Tor 0.2.5.3-alpha-dev on Linux\n"
-"protocols Link 1 2 Circuit 1\n"
-"published 2014-06-08 19:20:10\n"
-"fingerprint CC6A 48BD 52BD 9A2C 6670 5863 AC31 AE17 6E63 8B02\n"
-"uptime 0\n"
-"bandwidth 1073741824 1073741824 0\n"
-"extra-info-digest B5CC249CEF394B5AFCA0C77FA7D5605615FA487C\n"
-"onion-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAMze36Hupy7HACcF3TMv5mJuZbx3d3cS0WYLl6vTeChBgpS5CEXq6zIu\n"
-"d31YmtUcxH6fOjDOudhbnXuoh1nH4CP+LocVHAdlGG1giAm7u8yZudVvVJiIqFgQ\n"
-"wVDcWx8LbGCi5P9J/ZPKAIVsSyS7xkOqHjz3VMo/uYLbQCFAwfkdAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"signing-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAM/qGP365x6bH+ug7rKVy7V5lC9Ff2Jfk0wlTFIzzwn+DMSG6xDvulKe\n"
-"wcIzgGNdQu7qlKlQUif3GPMr0KSS32cRsmoRQJcsm9+lGUK871NyZ8AyrHT+LhyF\n"
-"cs718P0iN5yKF2FikNr727kEANCzvC1l9eP4qF5GGzsNtglbJ7bTAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"hidden-service-dir\n"
-"ntor-onion-key a9Pavqnx7DFhMWUO0d17qF9Py8+iie4FnxTHaTgfIXY=\n"
-"reject *:25\n"
-"reject *:119\n"
-"reject *:135-139\n"
-"reject *:445\n"
-"reject *:563\n"
-"reject *:1214\n"
-"reject *:4661-4666\n"
-"reject *:6346-6429\n"
-"reject *:6699\n"
-"reject *:6881-6999\n"
-"accept *:*\n"
-"router-signature\n"
-"-----BEGIN SIGNATURE-----\n"
-"HVW7kjBgEt+Qdvcrq+NQE1F9B8uV9D38KA2Bp6cYHLWCxL6N4GS8JQqbOEtnqaj7\n"
-"Vxrv7uy1Fzb15Zr+1sUVMxNv+LLRfr+JzfETMNYVkYDrNgr1cAAVEQzFWbIziond\n"
-"xMFp64yjEW9/I+82lb5GBZEiKdEd4QqWMmQosoYMTM8=\n"
-"-----END SIGNATURE-----\n"
-"@uploaded-at 2014-06-08 19:20:12\n"
-"@source \"127.0.0.1\"\n"
-"router test002a 127.0.0.1 5002 0 7002\n"
-"platform Tor 0.2.5.3-alpha-dev on Linux\n"
-"protocols Link 1 2 Circuit 1\n"
-"published 2014-06-08 19:20:11\n"
-"fingerprint 29C7 BBB6 C437 32D5 BDF1 5671 F5C5 F1FB 6E36 4B47\n"
-"uptime 0\n"
-"bandwidth 1073741824 1073741824 0\n"
-"extra-info-digest 9BB181EA86E0130680C3CC04AD7DE4C341ADC2C7\n"
-"caches-extra-info\n"
-"onion-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBALNH19oF8Ajf+djlH/g7L+enFBf5Wwjmf3bPwNKWZ9G+B+Lg8SpfhZiw\n"
-"rUqi7h21f45BV/dN05dK6leWD8rj1T9kuM9TKBOEZxIWeq7zbXihyu4XPxP4FNTS\n"
-"+0G7BhdP4biALENmeyLhUCZaw5Ic/jFkHT4gV9S0iVZiEDwC9twXAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"signing-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBALeyQGMQBHgTxpO/i30uHjflTm9MNi3ZBNcOKpvBXWYgY42qTqOZ7Uam\n"
-"c5pmZhTLrQ1W8XlGDw8Cl8ktZ0ylodLZyUNajBtJvSFWTb8iwdZsshW6Ahb8TyfI\n"
-"Y7MwTlQ/7xw4mj1NEaui6bwGgEZUs18RTqhDrUc2Mcj1Yf61Rq+7AgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"hidden-service-dir\n"
-"contact auth2@test.test\n"
-"ntor-onion-key ukR41RjtiZ69KO0SrFTvL0LoZK/ZTT01FQWmCXTCUlE=\n"
-"reject *:*\n"
-"router-signature\n"
-"-----BEGIN SIGNATURE-----\n"
-"IY2s/RY4tdahrgfGG+vW7lOvpfofoxxSo7guGpSKGxVApiroCQtumoYifnnJ88G2\n"
-"K4IbxwEO8pgO8fnz1mibblUWw2vdDNjCifc1wtXJUE+ONA0UcLRlfQ94GbL8h2PG\n"
-"72z6i1+NN0QahXMk7MUbzI7bOXTJOiO8e2Zjk9vRnxI=\n"
-"-----END SIGNATURE-----\n"
-"@uploaded-at 2014-06-08 19:20:12\n"
-"@source \"127.0.0.1\"\n"
-"router test006r 127.0.0.1 5006 0 7006\n"
-"platform Tor 0.2.5.3-alpha-dev on Linux\n"
-"protocols Link 1 2 Circuit 1\n"
-"published 2014-06-08 19:20:11\n"
-"fingerprint 829B 3FAA A42B 605A EB0B F380 8F32 8ED1 73E7 0D25\n"
-"uptime 0\n"
-"bandwidth 1073741824 1073741824 0\n"
-"extra-info-digest 7ECB757002EB9B5838B13AE6F2357A5E585131B8\n"
-"onion-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBALsNBChcLVndlS4HNXL3hxBJVgXctATz6yXcJt3bkDB5cjv7Q9fqN3Ue\n"
-"j3SI1OUBx4YrLcSLD/hELHVilLrrfbaraAFfAsydlRLjTVcMRx5FFlDd0E7TAadc\n"
-"71CkTipNnjwqz1mTRKkEFeepnh/JaFDidY9ER1rMBA5JRyBvqrD9AgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"signing-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAPgipA8yLj1kqrMlAH7cK7IQEdmqmfNHGXdkYQ+TKtfLh0zeEIvvh9yh\n"
-"k+vKHS+HVoHo3tecB9QjJyDyyJTiETXCupSOY+ebG648JADAvv8v1WiE+KBXtjpl\n"
-"qgDTrDj5CwGuY6cvQdej5yg1UAVlMMZSg3thL3tCYtQbOq66lAlnAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"hidden-service-dir\n"
-"ntor-onion-key q02F3AQsCX7+zXNpfTqBF8O8lusPhRJpQVxOnBvbOwc=\n"
-"reject *:25\n"
-"reject *:119\n"
-"reject *:135-139\n"
-"reject *:445\n"
-"reject *:563\n"
-"reject *:1214\n"
-"reject *:4661-4666\n"
-"reject *:6346-6429\n"
-"reject *:6699\n"
-"reject *:6881-6999\n"
-"accept *:*\n"
-"router-signature\n"
-"-----BEGIN SIGNATURE-----\n"
-"L1fdgoN/eXgdzIIXO63W4yGoC9lRozMU+T0Fimhd/XFV8qxeUT83Vgf63vxLUHIb\n"
-"D4a80Wj7Pm4y5a766qLGXxlz2FYjCdkp070UpgZneB+VifUlFd/bNAjsiYTstBKM\n"
-"EI2L0mhl9d/7KK8vgtadHdX1z1u7QjyF6ccnzhfqeiY=\n"
-"-----END SIGNATURE-----\n"
-"@uploaded-at 2014-06-08 19:20:12\n"
-"@source \"127.0.0.1\"\n"
-"router test003r 127.0.0.1 5003 0 7003\n"
-"platform Tor 0.2.5.3-alpha-dev on Linux\n"
-"protocols Link 1 2 Circuit 1\n"
-"published 2014-06-08 19:20:11\n"
-"fingerprint 71FD 3A35 F705 8020 D595 B711 D52A 9A0A 99BB B467\n"
-"uptime 0\n"
-"bandwidth 1073741824 1073741824 0\n"
-"extra-info-digest 3796BE0A95B699595445DFD3453CA2074E75BCE8\n"
-"onion-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAL44ctIioIfCYFzMTYNfK5qFAPGGUpsAFmS8pThQEY/tJU14+frJDBrC\n"
-"BkLvBs05Bw7xOUb0f2geiYGowBA6028smiq5HzTO7Kaga8vfV7AnANPX+n9cfHCr\n"
-"/2cMnKkT/GZzpdk0WbUw5Kc/G1ATIPFQHA8gZAi1fsSIDDn3GRV5AgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"signing-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBALlPo5AI1mVTi+194yOSf40caoFlxSTfXt8KjGVa1dO/bpX7L3noOjYg\n"
-"goU4Aqim7BHmBWQDE/tZNTrchFoLQFHi9N4pv/0ND3sY904pzqGpe3FeTuU8P9Jg\n"
-"q2w3MeO3GwG8CJf4FOdSkgi8UKkJhOld4g4kViQbrFLXfdFvnT/zAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"hidden-service-dir\n"
-"ntor-onion-key qluYCRrsesOTkavCLnNK6H1ToywyDquCyYeP0h/qol4=\n"
-"reject *:25\n"
-"reject *:119\n"
-"reject *:135-139\n"
-"reject *:445\n"
-"reject *:563\n"
-"reject *:1214\n"
-"reject *:4661-4666\n"
-"reject *:6346-6429\n"
-"reject *:6699\n"
-"reject *:6881-6999\n"
-"accept *:*\n"
-"router-signature\n"
-"-----BEGIN SIGNATURE-----\n"
-"d09K7rW/OpVzoUpfZXJuJW7a+P4pROCOZTgvDUIy/Nv+EAjcYqv95PlJ8cAMqnn3\n"
-"1oQibRmmQwn0OmG5cB8NaZiueaVIRheGzHEM8rndpHn5oFXdFvV7KKjScvfuBbTk\n"
-"RYME8XyawRaqsEZnwirDDlZuiZOjdQs8bbGsko3grJE=\n"
-"-----END SIGNATURE-----\n"
-"@uploaded-at 2014-06-08 19:20:12\n"
-"@source \"127.0.0.1\"\n"
-"router test005r 127.0.0.1 5005 0 7005\n"
-"platform Tor 0.2.5.3-alpha-dev on Linux\n"
-"protocols Link 1 2 Circuit 1\n"
-"published 2014-06-08 19:20:11\n"
-"fingerprint EB6E 42ED E6BF 5EE0 19F5 EFC1 53AD 094C 1327 7B76\n"
-"uptime 0\n"
-"bandwidth 1073741824 1073741824 0\n"
-"extra-info-digest C031EE4E1AE826C1E3C4E21D81C961869E63F5D2\n"
-"onion-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAMd9Fm4KTSjFDzEABPZ1fwBCC2DNgee6nAmlde8FRbCVfcIHRiJyv9YG\n"
-"h530yUJal3hBfiWwy/SBA4LDz1flNCEwJm81s3waj4T9c676dAOLPcnOcJM5SbaQ\n"
-"hYPDrIZLEZHAk+IoM+avKYYocwCJXwx6WTtsedF0wJBZ9mQAJERJAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"signing-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAKT7ldhV43S1CgoER/pU0Rigf0NzcSy25DQJrMRQnNmXnL03Dwuv/Iu7\n"
-"dCjgg64odnvSkXHFhkbjGcg8aXikvfbMyZTbsD8NrrP6FS6pfgPgZD9W2TK7QdHI\n"
-"QXwx1IYaaJK4nDUNfJhjrclydEdxmHbO1nLG1aS0ypn/G0EBpOSnAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"hidden-service-dir\n"
-"ntor-onion-key umFmyRPA0dIsi0CFYCbGIPe2+OUkyslTkKKDEohjQQg=\n"
-"reject *:25\n"
-"reject *:119\n"
-"reject *:135-139\n"
-"reject *:445\n"
-"reject *:563\n"
-"reject *:1214\n"
-"reject *:4661-4666\n"
-"reject *:6346-6429\n"
-"reject *:6699\n"
-"reject *:6881-6999\n"
-"accept *:*\n"
-"router-signature\n"
-"-----BEGIN SIGNATURE-----\n"
-"JiXEbqPgDPWEb9DzCYINRXfmvMIc/IRtvshS8Vmmn7DW67TrTLKCEAnisGo92gMA\n"
-"bhxGb9G5Mxq/8YqGoqdI2Vp6tfKlz/9AmjHzFAo01y42gafXIdr1oUS2RimA8jfF\n"
-"hwfQkbG0FYEsJrH3EUa8sMhcjsEaohK/kgklMR7OgQY=\n"
-"-----END SIGNATURE-----\n"
-"@uploaded-at 2014-06-08 19:20:12\n"
-"@source \"127.0.0.1\"\n"
-"router test007r 127.0.0.1 5007 0 7007\n"
-"platform Tor 0.2.5.3-alpha-dev on Linux\n"
-"protocols Link 1 2 Circuit 1\n"
-"published 2014-06-08 19:20:11\n"
-"fingerprint DABD 2AAF 8C9F 3B71 7839 9C08 DCD8 CD9D 341D 0002\n"
-"uptime 0\n"
-"bandwidth 1073741824 1073741824 0\n"
-"extra-info-digest F80104A0DFFB4EB429325D41D1F71E5BF8C6C726\n"
-"onion-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAL42fYAriR/JeB/9NpVq5Y5EEHca+ugIpaSdRfbopWDtFjXLEk2jmO5A\n"
-"KoAGIkTKDr7e9101x63H+0Nh/7w3uYs/WqTXEH8/1sHwe+0PY2HL0S6qhlOo6X54\n"
-"EfK0nDDBAWFOpyiAMHRk8JVikKb56+FVIhCJgi1RIbLIiUQK2/kxAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"signing-key\n"
-"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAKQj2U5hmB68V6NQBqD8DfIkJjovvM8t6nGfYpkT8ORsROnmgI5mjM38\n"
-"cmh5GIjY9RgoOWolLmsWQ4SXtS0FvrPft1M61UMTSHzlrEeuod5KenV7vGlX2TxT\n"
-"0DoA5TL9yY7CmxCk8CNRCtN/g7WocgIiP4KCIiEZ4VE6LIb6sxUnAgMBAAE=\n"
-"-----END RSA PUBLIC KEY-----\n"
-"hidden-service-dir\n"
-"ntor-onion-key 1UBS8rTlL39u9YxRJWhz+GTG1dS15VRi4au1i5qZOyI=\n"
-"reject *:25\n"
-"reject *:119\n"
-"reject *:135-139\n"
-"reject *:445\n"
-"reject *:563\n"
-"reject *:1214\n"
-"reject *:4661-4666\n"
-"reject *:6346-6429\n"
-"reject *:6699\n"
-"reject *:6881-6999\n"
-"accept *:*\n"
-"router-signature\n"
-"-----BEGIN SIGNATURE-----\n"
-"m7xHh+XPdLN+qcMLz1dBAEAmcdCFrtdseMHCc0FyAP2kXdayxqe3o2IOOHN++bTH\n"
-"Y5iHsZembsIJJ+D/d0YEKWKh42TUWCXBu0Gbfc4OcNuR6PFlTWO2wk7rDT3HOiFr\n"
-"pe3wJqZYkLxlBDamROAlMMRe71iag89H/4EulC18opw=\n"
-"-----END SIGNATURE-----\n";
+ "@uploaded-at 2020-10-13 13:27:09\n"
+ "@source \"127.0.0.1\"\n"
+ "router test001a 127.0.0.1 5001 0 7001\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABs1eAaaOTHiF5TNABkcl/U1x6qvlb8dyNBjuezXxF2wFLgrRAQAgBAD/a0Xx\n"
+ "SqkjrxcXc1h00vvkSqjNuGb4xYg1BZUoZnwegCQmxELY6fQ3m3EzYfSSl1tbP2u8\n"
+ "sN4SBJCsV7aRdoYebs80CnrsPiUecVdTwruODb+wAKqKSl3u7+qx8dd1yAI=\n"
+ "-----END ED25519 CERT-----\n"
+ "master-key-ed25519 /2tF8UqpI68XF3NYdNL75Eqozbhm+MWINQWVKGZ8HoA\n"
+ "or-address [::]:5001\n"
+ "platform Tor 0.4.5.0-alpha-dev on Linux\n"
+ "proto Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-3\n"
+ "published 2020-10-13 13:27:09\n"
+ "fingerprint 2403 20EC F589 C1F4 DC0B 864B 28AF 8113 59CE FD86\n"
+ "uptime 324426\n"
+ "bandwidth 1073741824 1073741824 640416\n"
+ "extra-info-digest FD0FEB6B7F99C2E9A3C98968F6FB2C61B1688760 FDt9yIgtRYfaANh+E7NV6MUAvOR7DcJIjjBkhGMN6Vs\n"
+ "caches-extra-info\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOrByE3R1SqUkYLMDDB408uliYrBj860aKU0sbS9F9xmxFONB4xHP6uA\n"
+ "MyBgHQGL91N30yZxWKkdRiuKpCZafxLrflx20U/JTijJugNWPBcLXG7pTaJsL7LQ\n"
+ "61WRwo7md8X5zRhSGd8Pisq2Ru2yDrd0DNfoxy2CSLJX0DN9aw4xAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALb83qDqIq7U75NuDnzZL/A1YvxMp/YqoxtKd2GuCOMRpu+DLpEJfAkB\n"
+ "0o9IP+CeCkT3JPP2irY+WEw8gLU9bx2VfdK4sm59Q7G0gWcfYsvn3wb3q43e0LOf\n"
+ "KQ/HMkZ+sJwQ5sCteAhGqbr9XNBfRE0bT5pyEZGKNg3ufCd1c7MLAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "Mr8P5CTgWB/J84yzF/zY4tnQixbFyNBXi+KXBVvRmFRKBKtRRf7NYKDlXpTWA+yv\n"
+ "lyVzzKyVlSreRIZbmS/VZrS0adj8EL8VAGVg3l/7ZumKFRB0JSiVpidd2yu0K8/2\n"
+ "qENpmGQbFco+6tj8dsxr4HrPaV7UBDxwjDR/2HADiiI=\n"
+ "-----END CROSSCERT-----\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABs2OAf9rRfFKqSOvFxdzWHTS++RKqM24ZvjFiDUFlShmfB6AAFr/gG3LV3nx\n"
+ "pFWmVimT3w4a9RX4sihTdCQKtYIO2JTSUaBnBBCGWNKL/pgMq13Y+fUnrrltFprb\n"
+ "ts9KP+yi/QU=\n"
+ "-----END ED25519 CERT-----\n"
+ "hidden-service-dir\n"
+ "contact auth1@test.test\n"
+ "ntor-onion-key rrw3paBStz7xhguZJDdjl/Tcpqwgv4u37Zi1zJcVNFk\n"
+ "reject *:*\n"
+ "tunnelled-dir-server\n"
+ "router-sig-ed25519 pVC4W6LarfI5xgQIjwoizvHiU6HXf0P9t7M4nWQfYduzNuIk3KPDVxZWfm+r3QDMBVDSBc9yAmFVmxFi4PfeAg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "KHkPXBETKq3xyIckAS8BfL5Numjx2f3wLxkkDbDtsJt4nhXuL3CyWwtQGGQOqo10\n"
+ "HJfxeV2FktxHjlW08BGp8/EwnOcHsJkKg2yOlJodYXln8ATsHaMDS6inllyACIfC\n"
+ "680xs6LMJlUh/7qjPK3if7ayD+vPDCh+5IXq4n4Rn3k=\n"
+ "-----END SIGNATURE-----\n"
+ "@uploaded-at 2020-10-13 13:27:10\n"
+ "@source \"127.0.0.1\"\n"
+ "router test002a 127.0.0.1 5002 0 7002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABs1eAW2RVTJizfLKok8vZjvtdSQfTkjJbwuBJJah89MpjJJ1AQAgBAD7AE/p\n"
+ "ZVnOoor55N3BTseFvzTESbjQVJkMEw2jNMmkMUeolbJlRtsklLCMGjY9H79EFdY1\n"
+ "QamhpTz5AR4IyKdruX5SD+h8ovvWQK/pvVD20rI7Em6Qbg8OVvEPaZwxQwo=\n"
+ "-----END ED25519 CERT-----\n"
+ "master-key-ed25519 +wBP6WVZzqKK+eTdwU7Hhb80xEm40FSZDBMNozTJpDE\n"
+ "or-address [::]:5002\n"
+ "platform Tor 0.4.5.0-alpha-dev on Linux\n"
+ "proto Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-3\n"
+ "published 2020-10-13 13:27:10\n"
+ "fingerprint 1849 2918 5A95 1CF2 DDA7 C3B0 1ACB 32D7 360C C4BF\n"
+ "uptime 324427\n"
+ "bandwidth 1073741824 1073741824 776649\n"
+ "extra-info-digest 8CB745E0CD4FD3E7E22739124F8FE88840CAFF05 f+jRe7cLSC7bCBEQfHhVxWYZbu5MXsdqQbFRAFhUFNo\n"
+ "caches-extra-info\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALkdaGnfYPMk4Gb6tEM0VkAHvf52ETyxn/yz876JzmbBqhMRz7BGMUKX\n"
+ "et6pLXZRrL0TbYbDkESCkWvOj9nq6pyxwoYcBTNBo/w3kdDk/RlVlc0egrvXQPgO\n"
+ "O0XJ3qjfW88aCyW4pr1XPpiLedj7GAMkHLXKSjHptKvkMH8UBIWrAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANf2NRv0Si2EBM/Bt055XgLdUAHJhAu+kI9/EOfZbHf/hXeV/NAA8QJB\n"
+ "TsqoN/v1krBFTUUZmushA7SAYJk69SipJDzYEOg3ZaaPVGanrLh7hiMTemgKh5j1\n"
+ "6ABIbUfZz4GufalIUzyVxF7qUNF7xZgKBzmxR7eW3jSabrEFdrPFAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "Q8rGB57opO5DQrRdIO4EoUphDbRNhIIYzs43UeZk+BDxYkMdMSMcmj7JqemH2AC1\n"
+ "yjOKbjy14w1cVmGvlXzvOKAA3ylpF7c3UkLhaVurKBmiZKXtZaWLns744QSGUbog\n"
+ "erN+WT0syXaXXEZGr6pPDtK9NJld/nMBw8TBGwNL8nc=\n"
+ "-----END CROSSCERT-----\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABs2OAfsAT+llWc6iivnk3cFOx4W/NMRJuNBUmQwTDaM0yaQxANuEvTxfukyO\n"
+ "lPKM02Lzm0hIvhFmbEqmekfwrqYG+avRmAeDc8eStlm8CQBw7LRJE++MJgAHWh9r\n"
+ "1tB3DcJxiQU=\n"
+ "-----END ED25519 CERT-----\n"
+ "hidden-service-dir\n"
+ "contact auth2@test.test\n"
+ "ntor-onion-key /vAbEzRKRi0j/0mrhyKBdNMxR56xnzl6fQvtHT/QcAE\n"
+ "reject *:*\n"
+ "tunnelled-dir-server\n"
+ "router-sig-ed25519 yo7QljYNLR1qIYtRUO4j769qUiDAOk4ueL1XQWFWi+TIenwiBc55fgUFQZAg3wgEwPM37CUdMkAMWKA2CQgSCw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "hYDgjk0GH3xiBOgAccLQntNTYWGmzEvjozZIfqh6IzJtAfZkqpg9O7xaEiMRmkwj\n"
+ "+BHuMHiLj9BIHrMAP89pW9SoK+UfQdzKEI6VLFz/Z3c7H9F2OHse5HVc01X0Z6w7\n"
+ "eCPEOYUid7JJuVcABnJjs5PDo81LLOzY3089xRepC+c=\n"
+ "-----END SIGNATURE-----\n"
+ "@uploaded-at 2020-10-13 13:27:12\n"
+ "@source \"127.0.0.1\"\n"
+ "router test000a 127.0.0.1 5000 0 7000\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABs1eAX4HwKEhOktiFqMiJKxeCjj6o9/7Q/2+ssa3coYnhbYaAQAgBAAaycSq\n"
+ "2pbQLnRy2Yn8wiUhsge+cD6Yq3e/Bgq8hgYgJzhFP3znXvYpZJ9dT1J+4G3ykeVE\n"
+ "RK0wTU8Utb/+2XfYbXoECmBlb0Hyb87gTsB20O/d1gBssxpIcrjXwyzh/wI=\n"
+ "-----END ED25519 CERT-----\n"
+ "master-key-ed25519 GsnEqtqW0C50ctmJ/MIlIbIHvnA+mKt3vwYKvIYGICc\n"
+ "or-address [::]:5000\n"
+ "platform Tor 0.4.5.0-alpha-dev on Linux\n"
+ "proto Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-3\n"
+ "published 2020-10-13 13:27:12\n"
+ "fingerprint F003 9DE0 BFF7 FCB9 F2AB BC3E 6936 9DC6 83B2 D429\n"
+ "uptime 324429\n"
+ "bandwidth 1073741824 1073741824 780830\n"
+ "extra-info-digest 6233C6BC8DAEE31AFBCD71C01C74B3EC7429F77F tEmOGBsYCTolEuqcAL6f4wpaVNn98Y/ONFyZUKxsRUY\n"
+ "caches-extra-info\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANLNgThrQ1xGSi/aV/pWQUwOe0uy/ITcU/MSng6orKp0yzzzXc8Ntjfi\n"
+ "EFXuD3aEk1lUgwOvRlO2xuiOoHAZNAmim6+h4OfBcFgTeRWbfSMOdaG6Fjvc62C8\n"
+ "JJ7kvQIsJoWyCN9QF9366dM8RWLGbzkJ1Ayq6FBcgx59zh6Du2w3AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMR2w3ESy+Nifvpvzx0ZlIaHzVa/prZIonYdGS95ZsCL8ImDUvPFswAq\n"
+ "Xf0DLF8bYMfaXQhnNsDsdyH4hlfEVrTua8ww06LPQaEw1qhC9gYfUxoHQ6s4f9yC\n"
+ "23KPMsw3MWnwdNspsVDjRgJlCH3JTWStNSB0TgHoRy3LYnKjzvldAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "A3PiP6XlMo9KAO+3Y9+znbqxSujOWNBJlgtQumqbTOCsnUp4tcZiqJx1Tnmd1pN5\n"
+ "ZPpiHl9Q4gJ7OcsgyRvNKHE1t0q+CSie5U5n70Zr6ygymcsfLGoV5E/wonmbRRyW\n"
+ "roEkTHQGXUtjZ6nWRGd6nhVcLCq/mfv2w7RWvkkEMyA=\n"
+ "-----END CROSSCERT-----\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABs2OARrJxKraltAudHLZifzCJSGyB75wPpird78GCryGBiAnADqu/a1EDc8r\n"
+ "SVN5RI6gC4nZRjPEg2kV4kPDTILGxTEDBfo8zwogr1gKWlclqFD4AVk/4W10hi+V\n"
+ "SRNLYyQfzgk=\n"
+ "-----END ED25519 CERT-----\n"
+ "hidden-service-dir\n"
+ "contact auth0@test.test\n"
+ "ntor-onion-key VLJF0ibPKRzAq/Qc9nCN9Eyv1JBk4EMBN9jQSQtxfGM\n"
+ "reject *:*\n"
+ "tunnelled-dir-server\n"
+ "router-sig-ed25519 +wqG2xtPPfF3Qg/xEvjxOXLjMr5NCX7muDM+sVUEXiPYpPkxxN39Y6XcSMYJf6KgmO5AmlU+7csL5OdQeENlAQ\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "q23Fmc55TMJhJW5bFN4BZKt5spInNdBtXIOj78WCpHheEY3LXs0LRiU5pOMQPIhR\n"
+ "BZ8lhToo72hZr0BErZqP0AAR+7yrKdvNKFp49opwfBCQAdw+a5UxvmCxyy2zebaW\n"
+ "UWHVtAUrohyct9Bd2Ji8mwohjRz/kxLAufUMtJVw1oE=\n"
+ "-----END SIGNATURE-----\n"
+ "@uploaded-at 2020-10-13 13:27:14\n"
+ "@source \"127.0.0.1\"\n"
+ "router test007r 127.0.0.1 5007 0 7007\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABs1eAYJYgXIkzMMOaM6v7/IOs5NUaPdVHwPgYWDTZ/3ju2vnAQAgBAAHB+2c\n"
+ "K3h4v+X4dzLh1Cl8U1hwUKBSmgE6KSE+oWeM6iZ8lEFJlMPA90v9hc1xnTe9zjjS\n"
+ "LkFWFIJcR3W54CJw56uTGcd0AcrCcJKph1tebIv+7y1Kz9i6SsZBpoWxcQI=\n"
+ "-----END ED25519 CERT-----\n"
+ "master-key-ed25519 BwftnCt4eL/l+Hcy4dQpfFNYcFCgUpoBOikhPqFnjOo\n"
+ "or-address [::]:5007\n"
+ "platform Tor 0.4.5.0-alpha-dev on Linux\n"
+ "proto Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-3\n"
+ "published 2020-10-13 13:27:14\n"
+ "fingerprint 53F5 0783 5270 D39A 1E47 62C6 8F5E D21F C5F7 F7E9\n"
+ "uptime 324431\n"
+ "bandwidth 1073741824 1073741824 777802\n"
+ "extra-info-digest CC5F5C9F98FEE42D36C186052C88F4AF08ABCE19 q9AA03Hu526wTSvrdqNdWIzjCr+OzUREXfO6HKF6/9s\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKHxn6yov5enz1uNzpMOtk74kEpwLvlcSmEGd0gwi3VPs6V64a9X15Ku\n"
+ "OD9TXWY4pcjXTGAUZ0IDEfLziAVpUUByVL7uMXD5Lm/5CoLEGgyBqsvAynK0JymR\n"
+ "uLJKkdKosR589jGyQpgb9yEk6n/VtlJUsTutsOgYgO/KFh/dmP/5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL5sykSg1TVaP0WNbydIhdC2fwBNkIlPv+wR9DbZ7+4b18vGmrQz8sgJ\n"
+ "ZpSyRmfe6jkZBOvPDPOLBCtU8+QptmPX6+w2AZhPXr8kpUfYRRrrnaWtMTzYKgmj\n"
+ "R/1lC29PWzDAl98TXid08H36jCUZwcbqrOmOBBQi6hzBOPz9syb7AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "CVKyWa+nJnimA22PG9+NMklfgCwWF8EUIhgbLNZAlnC16RHvwQsnAUeEs6frstin\n"
+ "UCZ84MXSntqn/Tore0Vs102BrSjv8uIFXaXEH8jRaLcDPeYJKyBXAOINtlVtc3Ze\n"
+ "faMUiR7X3cxZsoGJPeAYjLEKghIbEj2sMfWDqfTUeYk=\n"
+ "-----END CROSSCERT-----\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABs2OAQcH7ZwreHi/5fh3MuHUKXxTWHBQoFKaATopIT6hZ4zqACWhqDvK437I\n"
+ "OLfulZGKeyPcWCaMHjdYp9HByRW1xZhCV98maaTkpTCy7kGa0oaHGYl1hETMeIXN\n"
+ "1I8YTDv4pQM=\n"
+ "-----END ED25519 CERT-----\n"
+ "hidden-service-dir\n"
+ "ntor-onion-key vCYC3rCCj+emJh8uNnK3OcX2mRrgPWGgeka617QnGFM\n"
+ "accept *:*\n"
+ "tunnelled-dir-server\n"
+ "router-sig-ed25519 PnDFvJl9otq2sXsDkm023L9+VAftkADmn8ocYVU8z5UcpwQ/2ZrZOUBthWOgt+j7SuiOb6rDw4KT5zWNwSusDw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "H+/0VaNq9cX7GGj8s1ZWaaoLEuocakqcvZOUB4XoL5qmN3TCPfLMUDGM56EMkrvx\n"
+ "bzR6/iUm8RAK5bVoPMynYm3iJW7xwvXg6W4qTSIxaTX9SnZh03+UfnyPE3uykkSa\n"
+ "8+JZ6F9kqabWhi4yKsZtHt64A0/F+jyR5CvXl1kdt40=\n"
+ "-----END SIGNATURE-----\n"
+ "@uploaded-at 2020-10-13 13:27:14\n"
+ "@source \"127.0.0.1\"\n"
+ "router test006r 127.0.0.1 5006 0 7006\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABs1eAaRBmBZIcRzdZXo2qSBLNy9nZXvSyCmVMTbs+SLH8ozAAQAgBAANeGA+\n"
+ "qbvQAb9cMCjnGewaWlVp3xFaV2EWHV/IVnRmJodgXot9/W1v/eyGjzJ5mxTLLzDQ\n"
+ "a68Ry1NrLeDBX3ERX9XjiZ8YUrQlqWz8HsSZYdMoH7fDpaBG7SONxuCVqAo=\n"
+ "-----END ED25519 CERT-----\n"
+ "master-key-ed25519 DXhgPqm70AG/XDAo5xnsGlpVad8RWldhFh1fyFZ0ZiY\n"
+ "or-address [::]:5006\n"
+ "platform Tor 0.4.5.0-alpha-dev on Linux\n"
+ "proto Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-3\n"
+ "published 2020-10-13 13:27:14\n"
+ "fingerprint A0E2 FA39 D23F BB97 0B56 0C53 3BD8 B16D 0E63 548B\n"
+ "uptime 324431\n"
+ "bandwidth 1073741824 1073741824 347136\n"
+ "extra-info-digest BF56A5D6A1DB3090F4FE6AA37D0C4F97732AE49C B92bY5UKX7LVqvxvI4KZDlST1VQ+gy9IOO4SYIKdMnY\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALyNFEPoUDXHUprDPXMIKWoCeWDo4ztVh6yHJQE8v88tc3WiuBt7ExBP\n"
+ "3Hjrh10/julakjsQWqB/8neJc7lJqdnQqFp0G8KhViwRaWgxiMAAfgq9kRB8UDPD\n"
+ "GpgVGrvBB4mY9REnLlAeDjPK+rJ2ww5TSDe7GP5SYJh/5jBIAmShAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANnUmF9BJ77e1Vc+sIN+gXO4FGb+NYeEkzg8yTjlUCu/8eQCmNLjwO2A\n"
+ "S9cnfeK8vD0l7EgiYQWRUZRR5aK06VLDDbLZ6O5Kbey4gibgRCkXj85SGBsV0upr\n"
+ "rmozECBg3RshdvD1nRrubUYIbDQd5rH+XTYn7O42QVRodHuBJP2DAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "MsINH4fEw+GMWeLSxxmHfpSas1KEaX1RD0oo5GdyJjRs5Q2+ieDiW0T0VVN0auAp\n"
+ "niJoPf8er4oDjuJPuUTzsfiZUxBjCiMgLigdwI7FLFhbL/7dgZFzF+2a/JoFKbGv\n"
+ "2LKrEl0B8DsyG5aoF5T45eY5cx6fFXOkQjvYDEJ8cyM=\n"
+ "-----END CROSSCERT-----\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABs2OAQ14YD6pu9ABv1wwKOcZ7BpaVWnfEVpXYRYdX8hWdGYmANmc1AEsD0I4\n"
+ "+PKxTbE3RgpP0aUxiRBaQ3GGIvWyNZsix1bE1As/Y4N1/Vtn57b0eMd2xLokeEvG\n"
+ "JTGrTHoELA0=\n"
+ "-----END ED25519 CERT-----\n"
+ "hidden-service-dir\n"
+ "ntor-onion-key 2OKE+7fTI/CKOZ4bzzfSuNaSBzsBNlyjg7PJhWaMMmw\n"
+ "accept *:*\n"
+ "tunnelled-dir-server\n"
+ "router-sig-ed25519 Ez2DIieIvjFe8tZt5P4yOGuNH5Nw2PO6dD0hLylGhnk/elmG4hxf+qBj6LHybos88TP2fAh0mwceomGoUQQZDg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "dxOuYd7waHjZjfWMQwKWhJxrFA/z1dKwkAZSVwglSHCCD8EmAcuerxhTiEzmKJm1\n"
+ "areR0g1oNigVyQd8Y5gYam9lgLLM4vEyHVkRhgluzKBcWnwS1PAF4oYOvMxTqBuw\n"
+ "5dfhm58uU6h8/jeKL4J4VSNnYDwY6G4+YzOcQkU25sY=\n"
+ "-----END SIGNATURE-----\n"
+ "@uploaded-at 2020-10-13 13:27:14\n"
+ "@source \"127.0.0.1\"\n"
+ "router test004r 127.0.0.1 5004 0 7004\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABs1eATTDPEX+F/fXy60oU+qlU3kFPYm11GLFpGIkXJ3+ULD1AQAgBADBcugt\n"
+ "WlMsFJtdBOshhXHYNabLhZgnsHmlCrw6MR/qpwNL7TqsdPpsEvYKAuHSozOaof4V\n"
+ "4sy9Zd1NFvwOJLyp1QkErf4TXWDoMQUCir1AcPsj/AGDIGq48DFpZUZyego=\n"
+ "-----END ED25519 CERT-----\n"
+ "master-key-ed25519 wXLoLVpTLBSbXQTrIYVx2DWmy4WYJ7B5pQq8OjEf6qc\n"
+ "or-address [::]:5004\n"
+ "platform Tor 0.4.5.0-alpha-dev on Linux\n"
+ "proto Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-3\n"
+ "published 2020-10-13 13:27:14\n"
+ "fingerprint C763 47FA 498E 3929 F2AC 563C B958 1249 137F F656\n"
+ "uptime 324431\n"
+ "bandwidth 1073741824 1073741824 640261\n"
+ "extra-info-digest 93E7E827FA057EEACE951B7D3F26A1E8FCCBC12B sHuKfKSpRmXKocb79/PgbMfM7z6UcGbbgW3aQvQIuRE\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMFoSwvDavnsMuT8v5D9vcWATYziPOe6erYE1cWAKMLL6BIrqUhCKEIi\n"
+ "g2hKE7XeGypQURhtV/mkvx43N1NwMTzPlbkEtL1LdDmb1kKKxsQ0kSpX75yc6g8y\n"
+ "5aKLVjPBMRDk5+eszo0qHs/lOO+Pn0M5zBurWv6Jk12iN9ETMT6XAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOLXEVTTTkEqg47/I/JqORoqg/2r1bCa4LjPMThE6HoyvNIJRhGIsS18\n"
+ "37PZ3YGdkVY6bMdJWed4r4DGoqGu4I5p0hjv7CeONbGjIa19R4shkSKxGw8Prrr7\n"
+ "jHHg4eaK2i6p2bRPpn6V5Z/dAmfKz70682uKakZSsCA5hUoBMVr5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "ZO/f8nN9QYAm0O2SgaH5Zb9T6o5ibiKVC3N8nwzPzEA7xxli/OR81tCobHYoTDQt\n"
+ "ZYKZXLvH0LAmjdHVVOGYAyfQKR7Ig2djVQuB4VVf8ix31jpL8guUIG14IKI/XSnz\n"
+ "ZgHnGkAkhZC+Q+FHAc341DeSHBy9iZbwooXyuK+rfnM=\n"
+ "-----END CROSSCERT-----\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABs2OAcFy6C1aUywUm10E6yGFcdg1psuFmCeweaUKvDoxH+qnAJDQqV067Kgn\n"
+ "q56Hsi6zUgK87nX3ENuQuKtjl86uWq1QmpmMt259vMa/rouA61sglMDGsZ1YVgEC\n"
+ "yoUVkFxVkQM=\n"
+ "-----END ED25519 CERT-----\n"
+ "hidden-service-dir\n"
+ "ntor-onion-key XBpzf4GSuvJZ/PP0PM4ECNotP/VOtHcFimQ2COb+NGA\n"
+ "accept *:*\n"
+ "tunnelled-dir-server\n"
+ "router-sig-ed25519 fUGEaiokY5dyMBtQ7x6BWBKwsJC6MQVYfewSMiWagE+T8H2EY2Lww0yowQo0+40FIKSG4g6GNpSMvs1g0cYIAg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "h/nND9oB+dIiHzm93xm2Fi9pemP4B5B5qJkyEJg/CcpitaXvugBIw1EOWMwqrsr2\n"
+ "x7ZyDz8gUp7WcXwhqbXlsLgSFT96RC4cBG6Qjvly0t+gvvcxG7RHV2ytJ7VlakyP\n"
+ "uENuwPYre230OfOjm5Jg+wFdlF6OMLphj2Yd7o48Xcw=\n"
+ "-----END SIGNATURE-----\n"
+ "@uploaded-at 2020-10-13 13:27:34\n"
+ "@source \"127.0.0.1\"\n"
+ "router test005r 127.0.0.1 5005 0 7005\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABs1eAfTuBhu6ypB5/9avDiY3qBzulkCvfYqbFN/ABk/o4xFcAQAgBAAnmWRG\n"
+ "rIvqpb4Kk3cThEiWAll4uDCO2Y46uNm9WG7AtPt4LG+XfktG3GAxv6aVQimwlyHc\n"
+ "1x2Lfm9KG3mWWj+hxnum4Z7873OE0B9l2Hg0YQZCW/PuHSWN0rspTvY5SgA=\n"
+ "-----END ED25519 CERT-----\n"
+ "master-key-ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n"
+ "or-address [::]:5005\n"
+ "platform Tor 0.4.5.0-alpha-dev on Linux\n"
+ "proto Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-3\n"
+ "published 2020-10-13 13:27:34\n"
+ "fingerprint D219 590A C951 3BCD EBBA 9AB7 2100 7A4C C01B BAE3\n"
+ "uptime 324451\n"
+ "bandwidth 1073741824 1073741824 637796\n"
+ "extra-info-digest 78E6D382BC826B95B4111554EEE7D541A32AAAA3 c61Onjpq+1S0TrdvoaOvGAxew6yfO+uHNhipbemQmgA\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n"
+ "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n"
+ "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANBzejGAwyPTPq2Gm03wpg3qICo0uDQau8opude2mW3eyxAqOqHzC8De\n"
+ "gRgbmn040vqe9gwvH4iaHpVeTxyDwQefbfULdq6bETmX3aSUj6LKBCqqcyuOJFQu\n"
+ "7M2QfNSfHtldUABpIaqFvEA3AV8qjOoUtauoFNJKMy7Wj2//S70VAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "pD3Nkkunt8zP6PO6H3uHT0t7xnorC7cY/KfF75mFB+90pHCD9f0Xdu3Pjrur/q23\n"
+ "PIKV3hdtdsODoJuoh8LPGNAjS5rO6HMCtHNDNunNOs69bvfaO0jThnurXmOpY0sW\n"
+ "eRfBeYN2KNgrN0B1eDejfPSr03dkFY48yoUDROv9EJQ=\n"
+ "-----END CROSSCERT-----\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABs2OASeZZEasi+qlvgqTdxOESJYCWXi4MI7Zjjq42b1YbsC0AKc5y5qYUYvw\n"
+ "VATtWkV9DVIZbZSb9mQP5pmNaqmX+DbmINCYt8j7l+U7g3ftUyh0Wlrgevx0pFUI\n"
+ "RcIU0HKHZQA=\n"
+ "-----END ED25519 CERT-----\n"
+ "hidden-service-dir\n"
+ "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA\n"
+ "accept *:*\n"
+ "tunnelled-dir-server\n"
+ "router-sig-ed25519 Xm56dYbo/hCHWyzcdUPmfTeZ4qly2TYf1/2Q1lXKQDMJyBti8ZE8R2TTYsYimr+UtAapbzBItccZLze505nhBw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "bbeN0lq6nCfJQXGcKa1M9TQ6b2upig7clrlVXuzKeR0JhGwnDCXUAFxDtrw3vkVo\n"
+ "ExBXXvJeBPyustFOQkdiAEWHHSW5CwEgeVCBYZeEnaiySIgDVKuu+9B53ezFdC0Y\n"
+ "iFJkKxxDx7ksxX0zdl7aPT4ORFEuRhCYS6el7YJmoyg=\n"
+ "-----END SIGNATURE-----\n"
+ "@uploaded-at 2020-10-13 13:28:13\n"
+ "@source \"127.0.0.1\"\n"
+ "router test003r 127.0.0.1 5003 0 7003\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABs1eAUC9IBXmVO3yeYhG6VI5o6+uyPI8tNFBR38n8RDxW91MAQAgBAD6reoi\n"
+ "ucfyRvLfC++3TyajT1IHbggd8/D5Gp9DlzbDf4vRNbII2iCDxilKG60yNurDcDWA\n"
+ "W9H2JRwrZpiQgQvEzGQJRISaGHQIVlEKpER7RvjDZvQG9KtHyDdH0txcdgo=\n"
+ "-----END ED25519 CERT-----\n"
+ "master-key-ed25519 +q3qIrnH8kby3wvvt08mo09SB24IHfPw+RqfQ5c2w38\n"
+ "or-address [::]:5003\n"
+ "platform Tor 0.4.5.0-alpha-dev on Linux\n"
+ "proto Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-3\n"
+ "published 2020-10-13 13:28:13\n"
+ "fingerprint 09C5 1D0C D3F4 F3D5 8C73 D219 9BF3 F0FC 55F5 2965\n"
+ "uptime 324490\n"
+ "bandwidth 1073741824 1073741824 640359\n"
+ "extra-info-digest 64AD921120758875124DEBC83808AE282BEA76F6 6xEyhjSnACEk+bScEqhoTI43p4+bcnFh8E+9fvBdeow\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANQMTqT/mcGSnwA7MsqKrtmK0re+XsJesFNeRwozZLKLgsB0ARoHvlAp\n"
+ "iBb/9kU++GhRBUs3EsMaU7rHN+yahDzwrVlWgRm3YV17aj1guQnHm8RaTbDtKCii\n"
+ "G0aBo2quU1LqXot/XVOE2BCFO0DO+4tZE5mCChpnALy0AYs2Dj4HAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAJ2yCCvgp0/HYyvW+DIX+nMEZ8Q1Sjzke9oEVcx1UQKFDmCCRJA4cJA5\n"
+ "xx5hVedkIXug7DJ/2xkMR+QT+Cwqxij1K0jlJlOmnixsT/TnwyyhP6eIxNef0HuG\n"
+ "MAgptAEMltR9OqDEESvfGv0cz+U4fru6xHpfH9c/P4S3aeihUbSnAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "UaR88eoWRuFJjYqns3RP92bgZv5AKYjxNrcm0SpZIOgDeayq/1mDA/jdVbDPa4de\n"
+ "KRJ9ezXCo+2O2zl6rhvsRsMgVwrZEr5Hz4+Zf1H6hpvk8NoOEBCb5g3jef6nMmGr\n"
+ "1p+NV/OULow266pKnWidPQCWLjc+ladBLQU8EJxT65Q=\n"
+ "-----END CROSSCERT-----\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABs2OAfqt6iK5x/JG8t8L77dPJqNPUgduCB3z8Pkan0OXNsN/AGVx0xPqhPuo\n"
+ "n9nnmtt+48y9Wkcdo43Si3Nrl96TxAiOMB0NKoTIk7++puAreR364CBPM8LM0TrT\n"
+ "AxIjl/GuMQE=\n"
+ "-----END ED25519 CERT-----\n"
+ "hidden-service-dir\n"
+ "ntor-onion-key bLeD2EdnozYyTnxk9PeRykzjPEw65lVLmlBhWk5+ATI\n"
+ "accept *:*\n"
+ "tunnelled-dir-server\n"
+ "router-sig-ed25519 wGsA4xlKdM0rzborPOil8cvAzUS2ImXvsm9PgTQDiosGf8ve3ucdDUjKLNOTd6iFVDIl4ESG2Y3eOsqAgQddBA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "k8ndhNl9lCng7IfgeoYGWKnvmxgfo41M9Sq3754HUAVRJcVZ1RJm4OGI/Z/fw38I\n"
+ "ievnndu81y/L2cuHnSr+MTXY7B2pLXueOo8YpKlx799Wugn5dnfOhz9WHkFNhWQL\n"
+ "8iOty3iG3VIJVi0pU3qgj5Xc1zKVa3pZ/QQfs4k/g44=\n"
+ "-----END SIGNATURE-----\n";
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 4c074d0c3e..63cc621964 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -8,10 +8,10 @@
#define BWAUTH_PRIVATE
#define CONFIG_PRIVATE
-#define CONTROL_PRIVATE
+#define CONTROL_GETINFO_PRIVATE
+#define DIRAUTH_SYS_PRIVATE
#define DIRCACHE_PRIVATE
#define DIRCLIENT_PRIVATE
-#define DIRSERV_PRIVATE
#define DIRVOTE_PRIVATE
#define DLSTATUS_PRIVATE
#define HIBERNATE_PRIVATE
@@ -26,14 +26,16 @@
#include "core/or/or.h"
#include "app/config/config.h"
-#include "app/config/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "core/mainloop/connection.h"
#include "core/or/relay.h"
+#include "core/or/protover.h"
#include "core/or/versions.h"
#include "feature/client/bridges.h"
#include "feature/client/entrynodes.h"
-#include "feature/control/control.h"
+#include "feature/control/control_getinfo.h"
#include "feature/dirauth/bwauth.h"
+#include "feature/dirauth/dirauth_sys.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/dsigs_parse.h"
#include "feature/dirauth/process_descs.h"
@@ -46,10 +48,11 @@
#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"
+#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nickname.h"
#include "feature/nodelist/node_select.h"
@@ -71,13 +74,16 @@
#include "lib/memarea/memarea.h"
#include "lib/osinfo/uname.h"
#include "test/log_test_helpers.h"
+#include "test/opts_test_helpers.h"
#include "test/test.h"
#include "test/test_dir_common.h"
#include "core/or/addr_policy_st.h"
+#include "feature/dirauth/dirauth_options_st.h"
#include "feature/nodelist/authority_cert_st.h"
#include "feature/nodelist/document_signature_st.h"
#include "feature/nodelist/extrainfo_st.h"
+#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/networkstatus_voter_info_st.h"
#include "feature/dirauth/ns_detached_signatures_st.h"
@@ -91,8 +97,34 @@
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
-#define NS_MODULE dir
+static void setup_ei_digests(void);
+static uint8_t digest_ei_minimal[20];
+static uint8_t digest_ei_bad_nickname[20];
+static uint8_t digest_ei_maximal[20];
+static uint8_t digest_ei_bad_tokens[20];
+static uint8_t digest_ei_bad_sig2[20];
+static uint8_t digest_ei_bad_published[20];
+
+static networkstatus_t *
+networkstatus_parse_vote_from_string_(const char *s,
+ const char **eos_out,
+ enum networkstatus_type_t ns_type)
+{
+ size_t len = strlen(s);
+ // memdup so that it won't be nul-terminated.
+ char *tmp = tor_memdup(s, len);
+ networkstatus_t *result =
+ networkstatus_parse_vote_from_string(tmp, len, eos_out, ns_type);
+ if (eos_out && *eos_out) {
+ *eos_out = s + (*eos_out - tmp);
+ }
+ tor_free(tmp);
+ return result;
+}
static void
test_dir_nicknames(void *arg)
@@ -142,6 +174,266 @@ test_dir_nicknames(void *arg)
;
}
+/* Allocate and return a new routerinfo, with the fields set from the
+ * arguments to this function.
+ *
+ * Also sets:
+ * - random RSA identity and onion keys,
+ * - the platform field using get_platform_str(), and
+ * - supports_tunnelled_dir_requests to 1.
+ *
+ * If rsa_onion_keypair_out is not NULL, it is set to the onion keypair.
+ * The caller must free this keypair.
+ */
+static routerinfo_t *
+basic_routerinfo_new(const char *nickname, uint32_t ipv4_addr,
+ uint16_t or_port, uint16_t dir_port,
+ uint32_t bandwidthrate, uint32_t bandwidthburst,
+ uint32_t bandwidthcapacity,
+ time_t published_on,
+ crypto_pk_t **rsa_onion_keypair_out)
+{
+ char platform[256];
+
+ tor_assert(nickname);
+
+ crypto_pk_t *pk1 = NULL, *pk2 = NULL;
+ /* These keys are random: idx is ignored. */
+ pk1 = pk_generate(0);
+ pk2 = pk_generate(1);
+
+ tor_assert(pk1);
+ tor_assert(pk2);
+
+ get_platform_str(platform, sizeof(platform));
+
+ routerinfo_t *r1 = tor_malloc_zero(sizeof(routerinfo_t));
+
+ r1->nickname = tor_strdup(nickname);
+ r1->platform = tor_strdup(platform);
+
+ tor_addr_from_ipv4h(&r1->ipv4_addr, ipv4_addr);
+ r1->ipv4_orport = or_port;
+ r1->ipv4_dirport = dir_port;
+ r1->supports_tunnelled_dir_requests = 1;
+
+ router_set_rsa_onion_pkey(pk1, &r1->onion_pkey, &r1->onion_pkey_len);
+ r1->identity_pkey = pk2;
+
+ r1->bandwidthrate = bandwidthrate;
+ r1->bandwidthburst = bandwidthburst;
+ r1->bandwidthcapacity = bandwidthcapacity;
+
+ r1->cache_info.published_on = published_on;
+ r1->protocol_list = tor_strdup(protover_get_supported_protocols());
+
+ if (rsa_onion_keypair_out) {
+ *rsa_onion_keypair_out = pk1;
+ } else {
+ crypto_pk_free(pk1);
+ }
+
+ return r1;
+}
+
+/* Allocate and return a new string containing a "router" line for r1. */
+static char *
+get_new_router_line(const routerinfo_t *r1)
+{
+ char *line = NULL;
+
+ tor_assert(r1);
+
+ tor_asprintf(&line,
+ "router %s %s %d 0 %d\n",
+ r1->nickname, fmt_addr(&r1->ipv4_addr),
+ r1->ipv4_orport, r1->ipv4_dirport);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing a "platform" line for the
+ * current Tor version and OS. */
+static char *
+get_new_platform_line(void)
+{
+ char *line = NULL;
+
+ tor_asprintf(&line,
+ "platform Tor %s on %s\n",
+ VERSION, get_uname());
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing a "published" line for r1.
+ * r1->cache_info.published_on must be between 0 and 59 seconds. */
+static char *
+get_new_published_line(const routerinfo_t *r1)
+{
+ char *line = NULL;
+
+ tor_assert(r1);
+
+ tor_assert(r1->cache_info.published_on >= 0);
+ tor_assert(r1->cache_info.published_on <= 59);
+
+ tor_asprintf(&line,
+ "published 1970-01-01 00:00:%02u\n",
+ (unsigned)r1->cache_info.published_on);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing a "fingerprint" line for r1. */
+static char *
+get_new_fingerprint_line(const routerinfo_t *r1)
+{
+ char *line = NULL;
+ char fingerprint[FINGERPRINT_LEN+1];
+
+ tor_assert(r1);
+
+ tor_assert(!crypto_pk_get_fingerprint(r1->identity_pkey, fingerprint, 1));
+ tor_assert(strlen(fingerprint) > 0);
+
+ tor_asprintf(&line,
+ "fingerprint %s\n",
+ fingerprint);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing an "uptime" line with uptime t.
+ *
+ * You should pass a hard-coded value to this function, because even if we made
+ * it reflect uptime, that still wouldn't make it right, because the two
+ * descriptors might be made on different seconds.
+ */
+static char *
+get_new_uptime_line(time_t t)
+{
+ char *line = NULL;
+
+ tor_asprintf(&line,
+ "uptime %u\n",
+ (unsigned)t);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing an "bandwidth" line for r1.
+ */
+static char *
+get_new_bandwidth_line(const routerinfo_t *r1)
+{
+ char *line = NULL;
+
+ tor_assert(r1);
+
+ tor_asprintf(&line,
+ "bandwidth %u %u %u\n",
+ r1->bandwidthrate,
+ r1->bandwidthburst,
+ r1->bandwidthcapacity);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing a key_name block for the
+ * RSA key pk1.
+ */
+static char *
+get_new_rsa_key_block(const char *key_name, crypto_pk_t *pk1)
+{
+ char *block = NULL;
+ char *pk1_str = NULL;
+ size_t pk1_str_len = 0;
+
+ tor_assert(key_name);
+ tor_assert(pk1);
+
+ tor_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str,
+ &pk1_str_len));
+ tor_assert(pk1_str);
+ tor_assert(pk1_str_len);
+
+ tor_asprintf(&block,
+ "%s\n%s",
+ key_name,
+ pk1_str);
+ tor_free(pk1_str);
+
+ tor_assert(block);
+ return block;
+}
+
+/* Allocate and return a new string containing an "onion-key" block for the
+ * router r1.
+ */
+static char *
+get_new_onion_key_block(const routerinfo_t *r1)
+{
+ char *block = NULL;
+ tor_assert(r1);
+ crypto_pk_t *pk_tmp = router_get_rsa_onion_pkey(r1->onion_pkey,
+ r1->onion_pkey_len);
+ block = get_new_rsa_key_block("onion-key", pk_tmp);
+ crypto_pk_free(pk_tmp);
+ return block;
+}
+
+/* Allocate and return a new string containing an "signing-key" block for the
+ * router r1.
+ */
+static char *
+get_new_signing_key_block(const routerinfo_t *r1)
+{
+ tor_assert(r1);
+ return get_new_rsa_key_block("signing-key", r1->identity_pkey);
+}
+
+/* Allocate and return a new string containing an "ntor-onion-key" line for
+ * the curve25519 public key ntor_onion_pubkey.
+ */
+static char *
+get_new_ntor_onion_key_line(const curve25519_public_key_t *ntor_onion_pubkey)
+{
+ char *line = NULL;
+ char cert_buf[256];
+
+ tor_assert(ntor_onion_pubkey);
+
+ curve25519_public_to_base64(cert_buf, ntor_onion_pubkey, false);
+ tor_assert(strlen(cert_buf) > 0);
+
+ tor_asprintf(&line,
+ "ntor-onion-key %s\n",
+ cert_buf);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing a "bridge-distribution-request"
+ * line for options.
+ */
+static char *
+get_new_bridge_distribution_request_line(const or_options_t *options)
+{
+ if (options->BridgeRelay) {
+ return tor_strdup("bridge-distribution-request any\n");
+ } else {
+ return tor_strdup("");
+ }
+}
+
static smartlist_t *mocked_configured_ports = NULL;
/** Returns mocked_configured_ports */
@@ -151,71 +443,297 @@ mock_get_configured_ports(void)
return mocked_configured_ports;
}
-/** Run unit tests for router descriptor generation logic. */
+static crypto_pk_t *mocked_server_identitykey = NULL;
+
+/* Returns mocked_server_identitykey with no checks. */
+static crypto_pk_t *
+mock_get_server_identity_key(void)
+{
+ return mocked_server_identitykey;
+}
+
+static crypto_pk_t *mocked_onionkey = NULL;
+
+/* Returns mocked_onionkey with no checks. */
+static crypto_pk_t *
+mock_get_onion_key(void)
+{
+ return mocked_onionkey;
+}
+
+static routerinfo_t *mocked_routerinfo = NULL;
+
+/* Returns 0 and sets ri_out to mocked_routerinfo.
+ * ri_out must not be NULL. There are no other checks. */
+static int
+mock_router_build_fresh_unsigned_routerinfo(routerinfo_t **ri_out)
+{
+ tor_assert(ri_out);
+ *ri_out = mocked_routerinfo;
+ return 0;
+}
+
+static ed25519_keypair_t *mocked_master_signing_key = NULL;
+
+/* Returns mocked_master_signing_key with no checks. */
+static const ed25519_keypair_t *
+mock_get_master_signing_keypair(void)
+{
+ return mocked_master_signing_key;
+}
+
+static struct tor_cert_st *mocked_signing_key_cert = NULL;
+
+/* Returns mocked_signing_key_cert with no checks. */
+static const struct tor_cert_st *
+mock_get_master_signing_key_cert(void)
+{
+ return mocked_signing_key_cert;
+}
+
+static curve25519_keypair_t *mocked_curve25519_onion_key = NULL;
+
+/* Returns mocked_curve25519_onion_key with no checks. */
+static const curve25519_keypair_t *
+mock_get_current_curve25519_keypair(void)
+{
+ return mocked_curve25519_onion_key;
+}
+
+/* Unmock get_configured_ports() and free mocked_configured_ports. */
+static void
+cleanup_mock_configured_ports(void)
+{
+ UNMOCK(get_configured_ports);
+
+ if (mocked_configured_ports) {
+ SMARTLIST_FOREACH(mocked_configured_ports, port_cfg_t *, p, tor_free(p));
+ smartlist_free(mocked_configured_ports);
+ }
+}
+
+/* Mock get_configured_ports() with a list containing or_port and dir_port.
+ * If a port is 0, don't set it.
+ * Only sets the minimal data required for the tests to pass. */
+static void
+setup_mock_configured_ports(uint16_t or_port, uint16_t dir_port)
+{
+ cleanup_mock_configured_ports();
+
+ /* Fake just enough of an ORPort and DirPort to get by */
+ MOCK(get_configured_ports, mock_get_configured_ports);
+ mocked_configured_ports = smartlist_new();
+
+ if (or_port) {
+ port_cfg_t *or_port_cfg = tor_malloc_zero(sizeof(*or_port_cfg));
+ or_port_cfg->type = CONN_TYPE_OR_LISTENER;
+ or_port_cfg->addr.family = AF_INET;
+ or_port_cfg->port = or_port;
+ smartlist_add(mocked_configured_ports, or_port_cfg);
+ }
+
+ if (dir_port) {
+ port_cfg_t *dir_port_cfg = tor_malloc_zero(sizeof(*dir_port_cfg));
+ dir_port_cfg->type = CONN_TYPE_DIR_LISTENER;
+ dir_port_cfg->addr.family = AF_INET;
+ dir_port_cfg->port = dir_port;
+ smartlist_add(mocked_configured_ports, dir_port_cfg);
+ }
+}
+
+/* Clean up the data structures and unmock the functions needed for generating
+ * a fresh descriptor. */
+static void
+cleanup_mocks_for_fresh_descriptor(void)
+{
+ tor_free(get_options_mutable()->Nickname);
+
+ mocked_server_identitykey = NULL;
+ UNMOCK(get_server_identity_key);
+
+ crypto_pk_free(mocked_onionkey);
+ UNMOCK(get_onion_key);
+}
+
+/* Mock the data structures and functions needed for generating a fresh
+ * descriptor.
+ *
+ * Sets options->Nickname from r1->nickname.
+ * Mocks get_server_identity_key() with r1->identity_pkey.
+ *
+ * If rsa_onion_keypair is not NULL, it is used to mock get_onion_key().
+ * Otherwise, the public key in r1->onion_pkey is used to mock get_onion_key().
+ */
+static void
+setup_mocks_for_fresh_descriptor(const routerinfo_t *r1,
+ crypto_pk_t *rsa_onion_keypair)
+{
+ cleanup_mocks_for_fresh_descriptor();
+
+ tor_assert(r1);
+
+ /* router_build_fresh_signed_extrainfo() requires options->Nickname */
+ get_options_mutable()->Nickname = tor_strdup(r1->nickname);
+
+ /* router_build_fresh_signed_extrainfo() requires get_server_identity_key().
+ * Use the same one as the call to router_dump_router_to_string() above.
+ */
+ mocked_server_identitykey = r1->identity_pkey;
+ MOCK(get_server_identity_key, mock_get_server_identity_key);
+
+ /* router_dump_and_sign_routerinfo_descriptor_body() requires
+ * get_onion_key(). Use the same one as r1.
+ */
+ if (rsa_onion_keypair) {
+ mocked_onionkey = crypto_pk_dup_key(rsa_onion_keypair);
+ } else {
+ mocked_onionkey = router_get_rsa_onion_pkey(r1->onion_pkey,
+ r1->onion_pkey_len);
+ }
+ MOCK(get_onion_key, mock_get_onion_key);
+}
+
+/* Set options based on arg.
+ *
+ * b: BridgeRelay 1
+ * e: ExtraInfoStatistics 1
+ * s: sets all the individual statistics options to 1
+ *
+ * Always sets AssumeReachable to 1.
+ *
+ * Does not set ServerTransportPlugin, because it's parsed before use.
+ *
+ * Does not set BridgeRecordUsageByCountry, because the tests don't have access
+ * to a GeoIPFile or GeoIPv6File. */
+static void
+setup_dir_formats_options(const char *arg, or_options_t *options)
+{
+ /* Skip reachability checks for DirPort, ORPort, and tunnelled-dir-server */
+ options->AssumeReachable = 1;
+
+ if (strchr(arg, 'b')) {
+ options->BridgeRelay = 1;
+ }
+
+ if (strchr(arg, 'e')) {
+ options->ExtraInfoStatistics = 1;
+ }
+
+ if (strchr(arg, 's')) {
+ options->DirReqStatistics = 1;
+ options->HiddenServiceStatistics = 1;
+ options->EntryStatistics = 1;
+ options->CellStatistics = 1;
+ options->ExitPortStatistics = 1;
+ options->ConnDirectionStatistics = 1;
+ options->PaddingStatistics = 1;
+ }
+}
+
+/* Check that routerinfos r1 and rp1 are consistent.
+ * Only performs some basic checks.
+ */
+#define CHECK_ROUTERINFO_CONSISTENCY(r1, rp1) \
+STMT_BEGIN \
+ tt_assert(r1); \
+ tt_assert(rp1); \
+ tt_assert(tor_addr_eq(&rp1->ipv4_addr, &r1->ipv4_addr)); \
+ tt_int_op(rp1->ipv4_orport,OP_EQ, r1->ipv4_orport); \
+ tt_int_op(rp1->ipv4_dirport,OP_EQ, r1->ipv4_dirport); \
+ tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate); \
+ tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst); \
+ tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity); \
+ crypto_pk_t *rp1_onion_pkey = router_get_rsa_onion_pkey(rp1->onion_pkey, \
+ rp1->onion_pkey_len); \
+ crypto_pk_t *r1_onion_pkey = router_get_rsa_onion_pkey(r1->onion_pkey, \
+ r1->onion_pkey_len); \
+ tt_int_op(crypto_pk_cmp_keys(rp1_onion_pkey, r1_onion_pkey), OP_EQ, 0); \
+ crypto_pk_free(rp1_onion_pkey); \
+ crypto_pk_free(r1_onion_pkey); \
+ tt_int_op(crypto_pk_cmp_keys(rp1->identity_pkey, r1->identity_pkey), \
+ OP_EQ, 0); \
+ tt_int_op(rp1->supports_tunnelled_dir_requests, OP_EQ, \
+ r1->supports_tunnelled_dir_requests); \
+STMT_END
+
+/* Check that routerinfo r1 and extrainfo e1 are consistent.
+ * Only performs some basic checks.
+ */
+#define CHECK_EXTRAINFO_CONSISTENCY(r1, e1) \
+STMT_BEGIN \
+ tt_assert(r1); \
+ tt_assert(e1); \
+\
+ tt_str_op(e1->nickname, OP_EQ, r1->nickname); \
+STMT_END
+
+/* Check that the exit policy in rp2 is as expected. */
+#define CHECK_PARSED_EXIT_POLICY(rp2) \
+STMT_BEGIN \
+ tt_int_op(smartlist_len(rp2->exit_policy),OP_EQ, 2); \
+ \
+ p = smartlist_get(rp2->exit_policy, 0); \
+ tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_ACCEPT); \
+ tt_assert(tor_addr_is_null(&p->addr)); \
+ tt_int_op(p->maskbits,OP_EQ, 0); \
+ tt_int_op(p->prt_min,OP_EQ, 80); \
+ tt_int_op(p->prt_max,OP_EQ, 80); \
+ \
+ p = smartlist_get(rp2->exit_policy, 1); \
+ tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_REJECT); \
+ tt_assert(tor_addr_eq(&p->addr, &ex2->addr)); \
+ tt_int_op(p->maskbits,OP_EQ, 8); \
+ tt_int_op(p->prt_min,OP_EQ, 24); \
+ tt_int_op(p->prt_max,OP_EQ, 24); \
+STMT_END
+
+/** Run unit tests for router descriptor generation logic for a RSA + ed25519
+ * router.
+ */
static void
-test_dir_formats(void *arg)
+test_dir_formats_rsa_ed25519(void *arg)
{
char *buf = NULL;
- char buf2[8192];
- char platform[256];
- char fingerprint[FINGERPRINT_LEN+1];
- char *pk1_str = NULL, *pk2_str = NULL, *cp;
- size_t pk1_str_len, pk2_str_len;
- routerinfo_t *r1=NULL, *r2=NULL;
- crypto_pk_t *pk1 = NULL, *pk2 = NULL;
- routerinfo_t *rp1 = NULL, *rp2 = NULL;
- addr_policy_t *ex1, *ex2;
- routerlist_t *dir1 = NULL, *dir2 = NULL;
+ char *buf2 = NULL;
+ char *cp = NULL;
+
+ crypto_pk_t *r2_onion_pkey = NULL;
+ char cert_buf[256];
uint8_t *rsa_cc = NULL;
- or_options_t *options = get_options_mutable();
- const addr_policy_t *p;
time_t now = time(NULL);
- port_cfg_t orport, dirport;
- char cert_buf[256];
- (void)arg;
- pk1 = pk_generate(0);
- pk2 = pk_generate(1);
+ routerinfo_t *r2 = NULL;
+ extrainfo_t *e2 = NULL;
+ routerinfo_t *r2_out = NULL;
+ routerinfo_t *rp2 = NULL;
+ extrainfo_t *ep2 = NULL;
+ addr_policy_t *ex1, *ex2;
+ const addr_policy_t *p;
- tt_assert(pk1 && pk2);
+ smartlist_t *chunks = NULL;
+ int rv = -1;
+
+ or_options_t *options = get_options_mutable();
+ setup_dir_formats_options((const char *)arg, options);
hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);
- get_platform_str(platform, sizeof(platform));
- r1 = tor_malloc_zero(sizeof(routerinfo_t));
- r1->addr = 0xc0a80001u; /* 192.168.0.1 */
- r1->cache_info.published_on = 0;
- r1->or_port = 9000;
- r1->dir_port = 9003;
- r1->supports_tunnelled_dir_requests = 1;
- tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::");
- r1->ipv6_orport = 9999;
- router_set_rsa_onion_pkey(pk1, &r1->onion_pkey, &r1->onion_pkey_len);
+ /* r2 is a RSA + ed25519 descriptor, with an exit policy, but no DirPort or
+ * IPv6 */
+ r2 = basic_routerinfo_new("Fred", 0x0a030201u /* 10.3.2.1 */,
+ 9005, 0,
+ 3000, 3000, 3000,
+ 5,
+ &r2_onion_pkey);
+
/* Fake just enough of an ntor key to get by */
- curve25519_keypair_t r1_onion_keypair;
- curve25519_keypair_generate(&r1_onion_keypair, 0);
- r1->onion_curve25519_pkey = tor_memdup(&r1_onion_keypair.pubkey,
+ curve25519_keypair_t r2_onion_keypair;
+ curve25519_keypair_generate(&r2_onion_keypair, 0);
+ r2->onion_curve25519_pkey = tor_memdup(&r2_onion_keypair.pubkey,
sizeof(curve25519_public_key_t));
- r1->identity_pkey = crypto_pk_dup_key(pk2);
- r1->bandwidthrate = 1000;
- r1->bandwidthburst = 5000;
- r1->bandwidthcapacity = 10000;
- r1->exit_policy = NULL;
- r1->nickname = tor_strdup("Magri");
- r1->platform = tor_strdup(platform);
- ex1 = tor_malloc_zero(sizeof(addr_policy_t));
- ex2 = tor_malloc_zero(sizeof(addr_policy_t));
- ex1->policy_type = ADDR_POLICY_ACCEPT;
- tor_addr_from_ipv4h(&ex1->addr, 0);
- ex1->maskbits = 0;
- ex1->prt_min = ex1->prt_max = 80;
- ex2->policy_type = ADDR_POLICY_REJECT;
- tor_addr_from_ipv4h(&ex2->addr, 18<<24);
- ex2->maskbits = 8;
- ex2->prt_min = ex2->prt_max = 24;
- r2 = tor_malloc_zero(sizeof(routerinfo_t));
- r2->addr = 0x0a030201u; /* 10.3.2.1 */
+ /* Now add relay ed25519 keys
+ * We can't use init_mock_ed_keys() here, because the keys are seeded */
ed25519_keypair_t kp1, kp2;
ed25519_secret_key_from_seed(&kp1.seckey,
(const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
@@ -223,162 +741,85 @@ test_dir_formats(void *arg)
ed25519_secret_key_from_seed(&kp2.seckey,
(const uint8_t*)"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
ed25519_public_key_generate(&kp2.pubkey, &kp2.seckey);
- r2->cache_info.signing_key_cert = tor_cert_create(&kp1,
+ r2->cache_info.signing_key_cert = tor_cert_create_ed25519(&kp1,
CERT_TYPE_ID_SIGNING,
&kp2.pubkey,
now, 86400,
CERT_FLAG_INCLUDE_SIGNING_KEY);
- r2->platform = tor_strdup(platform);
- r2->cache_info.published_on = 5;
- r2->or_port = 9005;
- r2->dir_port = 0;
- r2->supports_tunnelled_dir_requests = 1;
- router_set_rsa_onion_pkey(pk2, &r2->onion_pkey, &r2->onion_pkey_len);
- curve25519_keypair_t r2_onion_keypair;
- curve25519_keypair_generate(&r2_onion_keypair, 0);
- r2->onion_curve25519_pkey = tor_memdup(&r2_onion_keypair.pubkey,
- sizeof(curve25519_public_key_t));
- r2->identity_pkey = crypto_pk_dup_key(pk1);
- r2->bandwidthrate = r2->bandwidthburst = r2->bandwidthcapacity = 3000;
+
+ /* Now add an exit policy */
+ ex1 = tor_malloc_zero(sizeof(addr_policy_t));
+ ex2 = tor_malloc_zero(sizeof(addr_policy_t));
+ ex1->policy_type = ADDR_POLICY_ACCEPT;
+ tor_addr_from_ipv4h(&ex1->addr, 0);
+ ex1->maskbits = 0;
+ ex1->prt_min = ex1->prt_max = 80;
+ ex2->policy_type = ADDR_POLICY_REJECT;
+ tor_addr_from_ipv4h(&ex2->addr, 18<<24);
+ ex2->maskbits = 8;
+ ex2->prt_min = ex2->prt_max = 24;
+
r2->exit_policy = smartlist_new();
smartlist_add(r2->exit_policy, ex1);
smartlist_add(r2->exit_policy, ex2);
- r2->nickname = tor_strdup("Fred");
- tt_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str,
- &pk1_str_len));
- tt_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str,
- &pk2_str_len));
-
- /* XXXX+++ router_dump_to_string should really take this from ri.*/
- options->ContactInfo = tor_strdup("Magri White "
- "<magri@elsewhere.example.com>");
- /* Skip reachability checks for DirPort and tunnelled-dir-server */
- options->AssumeReachable = 1;
-
- /* Fake just enough of an ORPort and DirPort to get by */
- MOCK(get_configured_ports, mock_get_configured_ports);
- mocked_configured_ports = smartlist_new();
-
- memset(&orport, 0, sizeof(orport));
- orport.type = CONN_TYPE_OR_LISTENER;
- orport.addr.family = AF_INET;
- orport.port = 9000;
- smartlist_add(mocked_configured_ports, &orport);
-
- memset(&dirport, 0, sizeof(dirport));
- dirport.type = CONN_TYPE_DIR_LISTENER;
- dirport.addr.family = AF_INET;
- dirport.port = 9003;
- smartlist_add(mocked_configured_ports, &dirport);
-
- buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL);
-
- UNMOCK(get_configured_ports);
- smartlist_free(mocked_configured_ports);
- mocked_configured_ports = NULL;
+ /* Fake just enough of an ORPort to get by */
+ setup_mock_configured_ports(r2->ipv4_orport, 0);
- tor_free(options->ContactInfo);
+ buf = router_dump_router_to_string(r2,
+ r2->identity_pkey, r2_onion_pkey,
+ &r2_onion_keypair, &kp2);
tt_assert(buf);
- strlcpy(buf2, "router Magri 192.168.0.1 9000 0 9003\n"
- "or-address [1:2:3:4::]:9999\n"
- "platform Tor "VERSION" on ", sizeof(buf2));
- strlcat(buf2, get_uname(), sizeof(buf2));
- strlcat(buf2, "\n"
- "published 1970-01-01 00:00:00\n"
- "fingerprint ", sizeof(buf2));
- tt_assert(!crypto_pk_get_fingerprint(pk2, fingerprint, 1));
- strlcat(buf2, fingerprint, sizeof(buf2));
- strlcat(buf2, "\nuptime 0\n"
- /* XXX the "0" above is hard-coded, but even if we made it reflect
- * uptime, that still wouldn't make it right, because the two
- * descriptors might be made on different seconds... hm. */
- "bandwidth 1000 5000 10000\n"
- "onion-key\n", sizeof(buf2));
- strlcat(buf2, pk1_str, sizeof(buf2));
- strlcat(buf2, "signing-key\n", sizeof(buf2));
- strlcat(buf2, pk2_str, sizeof(buf2));
- strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
- strlcat(buf2, "contact Magri White <magri@elsewhere.example.com>\n",
- sizeof(buf2));
- strlcat(buf2, "ntor-onion-key ", sizeof(buf2));
- base64_encode(cert_buf, sizeof(cert_buf),
- (const char*)r1_onion_keypair.pubkey.public_key, 32,
- BASE64_ENCODE_MULTILINE);
- strlcat(buf2, cert_buf, sizeof(buf2));
- strlcat(buf2, "reject *:*\n", sizeof(buf2));
- strlcat(buf2, "tunnelled-dir-server\nrouter-signature\n", sizeof(buf2));
- buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
- * twice */
+ cleanup_mock_configured_ports();
- tt_str_op(buf,OP_EQ, buf2);
- tor_free(buf);
+ chunks = smartlist_new();
- buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL);
- tt_assert(buf);
- cp = buf;
- rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
- tt_assert(rp1);
- tt_int_op(rp1->addr,OP_EQ, r1->addr);
- tt_int_op(rp1->or_port,OP_EQ, r1->or_port);
- tt_int_op(rp1->dir_port,OP_EQ, r1->dir_port);
- tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate);
- tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst);
- tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity);
- crypto_pk_t *onion_pkey = router_get_rsa_onion_pkey(rp1->onion_pkey,
- rp1->onion_pkey_len);
- tt_int_op(crypto_pk_cmp_keys(onion_pkey, pk1), OP_EQ, 0);
- crypto_pk_free(onion_pkey);
- tt_int_op(crypto_pk_cmp_keys(rp1->identity_pkey, pk2), OP_EQ, 0);
- tt_assert(rp1->supports_tunnelled_dir_requests);
- //tt_assert(rp1->exit_policy == NULL);
- tor_free(buf);
+ /* Synthesise a router descriptor, without the signatures */
+ smartlist_add(chunks, get_new_router_line(r2));
- strlcpy(buf2,
- "router Fred 10.3.2.1 9005 0 0\n"
- "identity-ed25519\n"
- "-----BEGIN ED25519 CERT-----\n", sizeof(buf2));
+ smartlist_add_strdup(chunks,
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n");
base64_encode(cert_buf, sizeof(cert_buf),
(const char*)r2->cache_info.signing_key_cert->encoded,
r2->cache_info.signing_key_cert->encoded_len,
BASE64_ENCODE_MULTILINE);
- strlcat(buf2, cert_buf, sizeof(buf2));
- strlcat(buf2, "-----END ED25519 CERT-----\n", sizeof(buf2));
- strlcat(buf2, "master-key-ed25519 ", sizeof(buf2));
+ smartlist_add_strdup(chunks, cert_buf);
+ smartlist_add_strdup(chunks, "-----END ED25519 CERT-----\n");
+
+ smartlist_add_strdup(chunks, "master-key-ed25519 ");
{
char k[ED25519_BASE64_LEN+1];
- tt_int_op(ed25519_public_to_base64(k,
- &r2->cache_info.signing_key_cert->signing_key),
- OP_GE, 0);
- strlcat(buf2, k, sizeof(buf2));
- strlcat(buf2, "\n", sizeof(buf2));
+ ed25519_public_to_base64(k, &r2->cache_info.signing_key_cert->signing_key);
+ smartlist_add_strdup(chunks, k);
+ smartlist_add_strdup(chunks, "\n");
}
- strlcat(buf2, "platform Tor "VERSION" on ", sizeof(buf2));
- strlcat(buf2, get_uname(), sizeof(buf2));
- strlcat(buf2, "\n"
- "published 1970-01-01 00:00:05\n"
- "fingerprint ", sizeof(buf2));
- tt_assert(!crypto_pk_get_fingerprint(pk1, fingerprint, 1));
- strlcat(buf2, fingerprint, sizeof(buf2));
- strlcat(buf2, "\nuptime 0\n"
- "bandwidth 3000 3000 3000\n", sizeof(buf2));
- strlcat(buf2, "onion-key\n", sizeof(buf2));
- strlcat(buf2, pk2_str, sizeof(buf2));
- strlcat(buf2, "signing-key\n", sizeof(buf2));
- strlcat(buf2, pk1_str, sizeof(buf2));
+
+ smartlist_add(chunks, get_new_platform_line());
+ smartlist_add_asprintf(chunks,
+ "proto %s\n", protover_get_supported_protocols());
+ smartlist_add(chunks, get_new_published_line(r2));
+ smartlist_add(chunks, get_new_fingerprint_line(r2));
+
+ smartlist_add(chunks, get_new_uptime_line(0));
+ smartlist_add(chunks, get_new_bandwidth_line(r2));
+
+ smartlist_add(chunks, get_new_onion_key_block(r2));
+ smartlist_add(chunks, get_new_signing_key_block(r2));
+
int rsa_cc_len;
- rsa_cc = make_tap_onion_key_crosscert(pk2,
+ rsa_cc = make_tap_onion_key_crosscert(r2_onion_pkey,
&kp1.pubkey,
- pk1,
+ r2->identity_pkey,
&rsa_cc_len);
tt_assert(rsa_cc);
base64_encode(cert_buf, sizeof(cert_buf), (char*)rsa_cc, rsa_cc_len,
BASE64_ENCODE_MULTILINE);
- strlcat(buf2, "onion-key-crosscert\n"
- "-----BEGIN CROSSCERT-----\n", sizeof(buf2));
- strlcat(buf2, cert_buf, sizeof(buf2));
- strlcat(buf2, "-----END CROSSCERT-----\n", sizeof(buf2));
+ smartlist_add_strdup(chunks, "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n");
+ smartlist_add_strdup(chunks, cert_buf);
+ smartlist_add_strdup(chunks, "-----END CROSSCERT-----\n");
int ntor_cc_sign;
{
tor_cert_t *ntor_cc = NULL;
@@ -393,112 +834,167 @@ test_dir_formats(void *arg)
BASE64_ENCODE_MULTILINE);
tor_cert_free(ntor_cc);
}
- tor_snprintf(buf2+strlen(buf2), sizeof(buf2)-strlen(buf2),
+ smartlist_add_asprintf(chunks,
"ntor-onion-key-crosscert %d\n"
"-----BEGIN ED25519 CERT-----\n"
"%s"
"-----END ED25519 CERT-----\n", ntor_cc_sign, cert_buf);
- strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
- strlcat(buf2, "ntor-onion-key ", sizeof(buf2));
- base64_encode(cert_buf, sizeof(cert_buf),
- (const char*)r2_onion_keypair.pubkey.public_key, 32,
- BASE64_ENCODE_MULTILINE);
- strlcat(buf2, cert_buf, sizeof(buf2));
- strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
- strlcat(buf2, "tunnelled-dir-server\n", sizeof(buf2));
- strlcat(buf2, "router-sig-ed25519 ", sizeof(buf2));
+ smartlist_add_strdup(chunks, "hidden-service-dir\n");
- /* Fake just enough of an ORPort to get by */
- MOCK(get_configured_ports, mock_get_configured_ports);
- mocked_configured_ports = smartlist_new();
+ smartlist_add(chunks, get_new_bridge_distribution_request_line(options));
+ smartlist_add(chunks, get_new_ntor_onion_key_line(&r2_onion_keypair.pubkey));
+ smartlist_add_strdup(chunks, "accept *:80\nreject 18.0.0.0/8:24\n");
+ smartlist_add_strdup(chunks, "tunnelled-dir-server\n");
- memset(&orport, 0, sizeof(orport));
- orport.type = CONN_TYPE_OR_LISTENER;
- orport.addr.family = AF_INET;
- orport.port = 9005;
- smartlist_add(mocked_configured_ports, &orport);
+ smartlist_add_strdup(chunks, "router-sig-ed25519 ");
- buf = router_dump_router_to_string(r2, pk1, pk2, &r2_onion_keypair, &kp2);
- tt_assert(buf);
- buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
+ size_t len_out = 0;
+ buf2 = smartlist_join_strings(chunks, "", 0, &len_out);
+ SMARTLIST_FOREACH(chunks, char *, s, tor_free(s));
+ smartlist_free(chunks);
+
+ tt_assert(len_out > 0);
+
+ buf[strlen(buf2)] = '\0'; /* Don't compare either sig; they're never the same
* twice */
tt_str_op(buf, OP_EQ, buf2);
tor_free(buf);
- buf = router_dump_router_to_string(r2, pk1, NULL, NULL, NULL);
+ setup_mock_configured_ports(r2->ipv4_orport, 0);
- UNMOCK(get_configured_ports);
- smartlist_free(mocked_configured_ports);
- mocked_configured_ports = NULL;
+ buf = router_dump_router_to_string(r2, r2->identity_pkey,
+ r2_onion_pkey,
+ &r2_onion_keypair, &kp2);
+ tt_assert(buf);
- /* Reset for later */
+ cleanup_mock_configured_ports();
+
+ /* Now, try to parse buf */
cp = buf;
rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
- tt_assert(rp2);
- tt_int_op(rp2->addr,OP_EQ, r2->addr);
- tt_int_op(rp2->or_port,OP_EQ, r2->or_port);
- tt_int_op(rp2->dir_port,OP_EQ, r2->dir_port);
- tt_int_op(rp2->bandwidthrate,OP_EQ, r2->bandwidthrate);
- tt_int_op(rp2->bandwidthburst,OP_EQ, r2->bandwidthburst);
- tt_int_op(rp2->bandwidthcapacity,OP_EQ, r2->bandwidthcapacity);
+
+ CHECK_ROUTERINFO_CONSISTENCY(r2, rp2);
+
tt_mem_op(rp2->onion_curve25519_pkey->public_key,OP_EQ,
r2->onion_curve25519_pkey->public_key,
CURVE25519_PUBKEY_LEN);
- onion_pkey = router_get_rsa_onion_pkey(rp2->onion_pkey,
- rp2->onion_pkey_len);
- tt_int_op(crypto_pk_cmp_keys(onion_pkey, pk2), OP_EQ, 0);
- crypto_pk_free(onion_pkey);
- tt_int_op(crypto_pk_cmp_keys(rp2->identity_pkey, pk1), OP_EQ, 0);
- tt_assert(rp2->supports_tunnelled_dir_requests);
-
- tt_int_op(smartlist_len(rp2->exit_policy),OP_EQ, 2);
-
- p = smartlist_get(rp2->exit_policy, 0);
- tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_ACCEPT);
- tt_assert(tor_addr_is_null(&p->addr));
- tt_int_op(p->maskbits,OP_EQ, 0);
- tt_int_op(p->prt_min,OP_EQ, 80);
- tt_int_op(p->prt_max,OP_EQ, 80);
-
- p = smartlist_get(rp2->exit_policy, 1);
- tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_REJECT);
- tt_assert(tor_addr_eq(&p->addr, &ex2->addr));
- tt_int_op(p->maskbits,OP_EQ, 8);
- tt_int_op(p->prt_min,OP_EQ, 24);
- tt_int_op(p->prt_max,OP_EQ, 24);
-
-#if 0
- /* Okay, now for the directories. */
- {
- fingerprint_list = smartlist_new();
- crypto_pk_get_fingerprint(pk2, buf, 1);
- add_fingerprint_to_dir(buf, fingerprint_list, 0);
- crypto_pk_get_fingerprint(pk1, buf, 1);
- add_fingerprint_to_dir(buf, fingerprint_list, 0);
+
+ CHECK_PARSED_EXIT_POLICY(rp2);
+
+ tor_free(buf);
+ routerinfo_free(rp2);
+
+ /* Test extrainfo creation. */
+
+ /* Set up standard mocks and data */
+ setup_mocks_for_fresh_descriptor(r2, r2_onion_pkey);
+
+ /* router_build_fresh_descriptor() requires
+ * router_build_fresh_unsigned_routerinfo(), but the implementation is
+ * too complex. Instead, we re-use r2.
+ */
+ mocked_routerinfo = r2;
+ MOCK(router_build_fresh_unsigned_routerinfo,
+ mock_router_build_fresh_unsigned_routerinfo);
+
+ /* r2 uses ed25519, so we need to mock the ed key functions */
+ mocked_master_signing_key = &kp2;
+ MOCK(get_master_signing_keypair, mock_get_master_signing_keypair);
+
+ mocked_signing_key_cert = r2->cache_info.signing_key_cert;
+ MOCK(get_master_signing_key_cert, mock_get_master_signing_key_cert);
+
+ mocked_curve25519_onion_key = &r2_onion_keypair;
+ MOCK(get_current_curve25519_keypair, mock_get_current_curve25519_keypair);
+
+ /* Fake just enough of an ORPort to get by */
+ setup_mock_configured_ports(r2->ipv4_orport, 0);
+
+ /* Test the high-level interface. */
+ rv = router_build_fresh_descriptor(&r2_out, &e2);
+ if (rv < 0) {
+ /* router_build_fresh_descriptor() frees r2 on failure. */
+ r2 = NULL;
+ /* Get rid of an alias to rp2 */
+ r2_out = NULL;
}
+ tt_assert(rv == 0);
+ tt_assert(r2_out);
+ tt_assert(e2);
+ /* Guaranteed by mock_router_build_fresh_unsigned_routerinfo() */
+ tt_ptr_op(r2_out, OP_EQ, r2);
+ /* Get rid of an alias to r2 */
+ r2_out = NULL;
+
+ /* Now cleanup */
+ cleanup_mocks_for_fresh_descriptor();
+
+ mocked_routerinfo = NULL;
+ UNMOCK(router_build_fresh_unsigned_routerinfo);
+ mocked_master_signing_key = NULL;
+ UNMOCK(get_master_signing_keypair);
+ mocked_signing_key_cert = NULL;
+ UNMOCK(get_master_signing_key_cert);
+ mocked_curve25519_onion_key = NULL;
+ UNMOCK(get_current_curve25519_keypair);
+
+ cleanup_mock_configured_ports();
+
+ CHECK_EXTRAINFO_CONSISTENCY(r2, e2);
+
+ /* Test that the signed ri is parseable */
+ tt_assert(r2->cache_info.signed_descriptor_body);
+ cp = r2->cache_info.signed_descriptor_body;
+ rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
-#endif /* 0 */
- dirserv_free_fingerprint_list();
+ CHECK_ROUTERINFO_CONSISTENCY(r2, rp2);
+
+ tt_mem_op(rp2->onion_curve25519_pkey->public_key,OP_EQ,
+ r2->onion_curve25519_pkey->public_key,
+ CURVE25519_PUBKEY_LEN);
+
+ CHECK_PARSED_EXIT_POLICY(rp2);
+
+ routerinfo_free(rp2);
+
+ /* Test that the signed ei is parseable */
+ tt_assert(e2->cache_info.signed_descriptor_body);
+ cp = e2->cache_info.signed_descriptor_body;
+ ep2 = extrainfo_parse_entry_from_string((const char*)cp,NULL,1,NULL,NULL);
+
+ CHECK_EXTRAINFO_CONSISTENCY(r2, ep2);
+
+ /* In future tests, we could check the actual extrainfo statistics. */
+
+ extrainfo_free(ep2);
done:
- if (r1)
- routerinfo_free(r1);
- if (r2)
- routerinfo_free(r2);
- if (rp2)
- routerinfo_free(rp2);
+ dirserv_free_fingerprint_list();
+
+ tor_free(options->Nickname);
+
+ cleanup_mock_configured_ports();
+ cleanup_mocks_for_fresh_descriptor();
+
+ if (chunks) {
+ SMARTLIST_FOREACH(chunks, char *, s, tor_free(s));
+ smartlist_free(chunks);
+ }
+
+ routerinfo_free(r2);
+ routerinfo_free(r2_out);
+ routerinfo_free(rp2);
+
+ extrainfo_free(e2);
+ extrainfo_free(ep2);
tor_free(rsa_cc);
+ crypto_pk_free(r2_onion_pkey);
+
tor_free(buf);
- tor_free(pk1_str);
- tor_free(pk2_str);
- if (pk1) crypto_pk_free(pk1);
- if (pk2) crypto_pk_free(pk2);
- if (rp1) routerinfo_free(rp1);
- tor_free(dir1); /* XXXX And more !*/
- tor_free(dir2); /* And more !*/
+ tor_free(buf2);
}
#include "failing_routerdescs.inc"
@@ -523,14 +1019,12 @@ test_dir_routerinfo_parsing(void *arg)
again = 999; \
ri = router_parse_entry_from_string((s), NULL, 0, 0, NULL, &again); \
tt_assert(ri == NULL); \
- tt_int_op(again, OP_EQ, (againval)); \
+ tt_int_op(again, OP_EQ, (againval)); \
} while (0)
CHECK_OK(EX_RI_MINIMAL);
CHECK_OK(EX_RI_MAXIMAL);
- CHECK_OK(EX_RI_MINIMAL_ED);
-
/* good annotations prepended */
routerinfo_free(ri);
ri = router_parse_entry_from_string(EX_RI_MINIMAL, NULL, 0, 0,
@@ -565,14 +1059,13 @@ test_dir_routerinfo_parsing(void *arg)
tt_ptr_op(ri, OP_EQ, NULL);
CHECK_FAIL(EX_RI_BAD_SIG1, 1);
- CHECK_FAIL(EX_RI_BAD_SIG2, 1);
CHECK_FAIL(EX_RI_BAD_TOKENS, 0);
CHECK_FAIL(EX_RI_BAD_PUBLISHED, 0);
CHECK_FAIL(EX_RI_NEG_BANDWIDTH, 0);
CHECK_FAIL(EX_RI_BAD_BANDWIDTH, 0);
CHECK_FAIL(EX_RI_BAD_BANDWIDTH2, 0);
- CHECK_FAIL(EX_RI_BAD_ONIONKEY1, 0);
- CHECK_FAIL(EX_RI_BAD_ONIONKEY2, 0);
+ CHECK_FAIL(EX_RI_BAD_BANDWIDTH3, 0);
+ CHECK_FAIL(EX_RI_BAD_ONIONKEY, 0);
CHECK_FAIL(EX_RI_BAD_PORTS, 0);
CHECK_FAIL(EX_RI_BAD_IP, 0);
CHECK_FAIL(EX_RI_BAD_DIRPORT, 0);
@@ -595,22 +1088,10 @@ test_dir_routerinfo_parsing(void *arg)
CHECK_FAIL(EX_RI_ED_BAD_SIG1, 0);
CHECK_FAIL(EX_RI_ED_BAD_SIG2, 0);
CHECK_FAIL(EX_RI_ED_BAD_SIG3, 0);
- CHECK_FAIL(EX_RI_ED_BAD_SIG4, 0);
CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT1, 0);
- CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT3, 0);
- CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT4, 0);
- CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT5, 0);
- CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT6, 0);
- CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT7, 0);
CHECK_FAIL(EX_RI_ED_MISPLACED1, 0);
CHECK_FAIL(EX_RI_ED_MISPLACED2, 0);
CHECK_FAIL(EX_RI_ED_BAD_CERT1, 0);
- CHECK_FAIL(EX_RI_ED_BAD_CERT2, 0);
- CHECK_FAIL(EX_RI_ED_BAD_CERT3, 0);
-
- /* This is allowed; we just ignore it. */
- CHECK_OK(EX_RI_BAD_EI_DIGEST);
- CHECK_OK(EX_RI_BAD_EI_DIGEST2);
#undef CHECK_FAIL
#undef CHECK_OK
@@ -666,14 +1147,10 @@ test_dir_extrainfo_parsing(void *arg)
tt_assert(ei->pending_sig);
CHECK_OK(EX_EI_MAXIMAL);
tt_assert(ei->pending_sig);
- CHECK_OK(EX_EI_GOOD_ED_EI);
- tt_assert(ei->pending_sig);
map = (struct digest_ri_map_t *)digestmap_new();
ADD(EX_EI_MINIMAL);
ADD(EX_EI_MAXIMAL);
- ADD(EX_EI_GOOD_ED_EI);
- ADD(EX_EI_BAD_FP);
ADD(EX_EI_BAD_NICKNAME);
ADD(EX_EI_BAD_TOKENS);
ADD(EX_EI_BAD_START);
@@ -683,8 +1160,6 @@ test_dir_extrainfo_parsing(void *arg)
ADD(EX_EI_ED_MISSING_CERT);
ADD(EX_EI_ED_BAD_CERT1);
ADD(EX_EI_ED_BAD_CERT2);
- ADD(EX_EI_ED_BAD_SIG1);
- ADD(EX_EI_ED_BAD_SIG2);
ADD(EX_EI_ED_MISPLACED_CERT);
ADD(EX_EI_ED_MISPLACED_SIG);
@@ -692,13 +1167,9 @@ test_dir_extrainfo_parsing(void *arg)
tt_ptr_op(ei->pending_sig, OP_EQ, NULL);
CHECK_OK(EX_EI_MAXIMAL);
tt_ptr_op(ei->pending_sig, OP_EQ, NULL);
- CHECK_OK(EX_EI_GOOD_ED_EI);
- tt_ptr_op(ei->pending_sig, OP_EQ, NULL);
CHECK_FAIL(EX_EI_BAD_SIG1,1);
- CHECK_FAIL(EX_EI_BAD_SIG2,1);
- CHECK_FAIL(EX_EI_BAD_SIG3,1);
- CHECK_FAIL(EX_EI_BAD_FP,0);
+ CHECK_FAIL(EX_EI_BAD_SIG2,0);
CHECK_FAIL(EX_EI_BAD_NICKNAME,0);
CHECK_FAIL(EX_EI_BAD_TOKENS,0);
CHECK_FAIL(EX_EI_BAD_START,0);
@@ -708,8 +1179,6 @@ test_dir_extrainfo_parsing(void *arg)
CHECK_FAIL(EX_EI_ED_MISSING_CERT,0);
CHECK_FAIL(EX_EI_ED_BAD_CERT1,0);
CHECK_FAIL(EX_EI_ED_BAD_CERT2,0);
- CHECK_FAIL(EX_EI_ED_BAD_SIG1,0);
- CHECK_FAIL(EX_EI_ED_BAD_SIG2,0);
CHECK_FAIL(EX_EI_ED_MISPLACED_CERT,0);
CHECK_FAIL(EX_EI_ED_MISPLACED_SIG,0);
@@ -766,11 +1235,14 @@ test_dir_parse_router_list(void *arg)
tt_mem_op(r->cache_info.signed_descriptor_body, OP_EQ,
EX_RI_MAXIMAL, strlen(EX_RI_MAXIMAL));
+ setup_ei_digests();
+
tt_int_op(2, OP_EQ, smartlist_len(invalid));
+
test_memeq_hex(smartlist_get(invalid, 0),
- "ab9eeaa95e7d45740185b4e519c76ead756277a9");
+ "10F951AF93AED0D3BC7FA5FFA232EB8C17747ACE");
test_memeq_hex(smartlist_get(invalid, 1),
- "9a651ee03b64325959e8f1b46f2b689b30750b4c");
+ "41D8723CDD4B1AADCCE538C28CDE7F69828C73D0");
/* Now tidy up */
SMARTLIST_FOREACH(dest, routerinfo_t *, rinfo, routerinfo_free(rinfo));
@@ -785,6 +1257,7 @@ test_dir_parse_router_list(void *arg)
ADD(EX_EI_MAXIMAL);
ADD(EX_EI_BAD_NICKNAME);
ADD(EX_EI_BAD_PUBLISHED);
+ ADD(EX_EI_BAD_SIG2);
cp = list;
tt_int_op(0,OP_EQ,
router_parse_list_from_string(&cp, NULL, dest, SAVED_NOWHERE,
@@ -797,11 +1270,16 @@ test_dir_parse_router_list(void *arg)
tt_mem_op(e->cache_info.signed_descriptor_body, OP_EQ,
EX_EI_MINIMAL, strlen(EX_EI_MINIMAL));
- tt_int_op(2, OP_EQ, smartlist_len(invalid));
- test_memeq_hex(smartlist_get(invalid, 0),
- "d5df4aa62ee9ffc9543d41150c9864908e0390af");
- test_memeq_hex(smartlist_get(invalid, 1),
- "f61efd2a7f4531f3687a9043e0de90a862ec64ba");
+ tt_int_op(3, OP_EQ, smartlist_len(invalid));
+ tt_mem_op(smartlist_get(invalid, 0),
+ OP_EQ,
+ digest_ei_bad_sig2, DIGEST_LEN);
+ tt_mem_op(smartlist_get(invalid, 1),
+ OP_EQ,
+ digest_ei_bad_nickname, DIGEST_LEN);
+ tt_mem_op(smartlist_get(invalid, 2),
+ OP_EQ,
+ digest_ei_bad_published, DIGEST_LEN);
done:
tor_free(list);
@@ -828,10 +1306,34 @@ test_dir_parse_router_list(void *arg)
static download_status_t dls_minimal;
static download_status_t dls_maximal;
static download_status_t dls_bad_fingerprint;
-static download_status_t dls_bad_sig2;
+static download_status_t dls_bad_sig1;
static download_status_t dls_bad_ports;
static download_status_t dls_bad_tokens;
+static uint8_t digest_minimal[20];
+static uint8_t digest_maximal[20];
+static uint8_t digest_bad_fingerprint[20];
+static uint8_t digest_bad_sig1[20];
+static uint8_t digest_bad_ports[20];
+static uint8_t digest_bad_tokens[20];
+
+static void
+setup_dls_digests(void)
+{
+#define SETUP(string, name) \
+ do { \
+ router_get_router_hash(string, strlen(string), (char*)digest_##name); \
+ } while (0)
+
+ SETUP(EX_RI_MINIMAL, minimal);
+ SETUP(EX_RI_MAXIMAL, maximal);
+ SETUP(EX_RI_BAD_FINGERPRINT, bad_fingerprint);
+ SETUP(EX_RI_BAD_SIG1, bad_sig1);
+ SETUP(EX_RI_BAD_PORTS, bad_ports);
+ SETUP(EX_RI_BAD_TOKENS, bad_tokens);
+#undef SETUP
+}
+
static int mock_router_get_dl_status_unrecognized = 0;
static int mock_router_get_dl_status_calls = 0;
@@ -839,24 +1341,22 @@ static download_status_t *
mock_router_get_dl_status(const char *d)
{
++mock_router_get_dl_status_calls;
- char hex[HEX_DIGEST_LEN+1];
- base16_encode(hex, sizeof(hex), d, DIGEST_LEN);
- if (!strcmp(hex, "3E31D19A69EB719C00B02EC60D13356E3F7A3452")) {
- return &dls_minimal;
- } else if (!strcmp(hex, "581D8A368A0FA854ECDBFAB841D88B3F1B004038")) {
- return &dls_maximal;
- } else if (!strcmp(hex, "2578AE227C6116CDE29B3F0E95709B9872DEE5F1")) {
- return &dls_bad_fingerprint;
- } else if (!strcmp(hex, "16D387D3A58F7DB3CF46638F8D0B90C45C7D769C")) {
- return &dls_bad_sig2;
- } else if (!strcmp(hex, "AB9EEAA95E7D45740185B4E519C76EAD756277A9")) {
- return &dls_bad_ports;
- } else if (!strcmp(hex, "A0CC2CEFAD59DBF19F468BFEE60E0868C804B422")) {
- return &dls_bad_tokens;
- } else {
- ++mock_router_get_dl_status_unrecognized;
- return NULL;
- }
+#define CHECK(name) \
+ do { \
+ if (fast_memeq(d, digest_##name, DIGEST_LEN)) \
+ return &dls_##name; \
+ } while (0)
+
+ CHECK(minimal);
+ CHECK(maximal);
+ CHECK(bad_fingerprint);
+ CHECK(bad_sig1);
+ CHECK(bad_ports);
+ CHECK(bad_tokens);
+
+ ++mock_router_get_dl_status_unrecognized;
+ return NULL;
+#undef CHECK
}
static void
@@ -875,21 +1375,23 @@ test_dir_load_routers(void *arg)
smartlist_add_strdup(wanted, hex_str(buf, DIGEST_LEN)); \
} while (0)
+ setup_dls_digests();
+
MOCK(router_get_dl_status_by_descriptor_digest, mock_router_get_dl_status);
update_approx_time(1412510400);
smartlist_add_strdup(chunks, EX_RI_MINIMAL);
smartlist_add_strdup(chunks, EX_RI_BAD_FINGERPRINT);
- smartlist_add_strdup(chunks, EX_RI_BAD_SIG2);
+ smartlist_add_strdup(chunks, EX_RI_BAD_SIG1);
smartlist_add_strdup(chunks, EX_RI_MAXIMAL);
smartlist_add_strdup(chunks, EX_RI_BAD_PORTS);
smartlist_add_strdup(chunks, EX_RI_BAD_TOKENS);
- /* not ADDing MINIMIAL */
+ /* not ADDing MINIMAL */
ADD(EX_RI_MAXIMAL);
ADD(EX_RI_BAD_FINGERPRINT);
- ADD(EX_RI_BAD_SIG2);
+ ADD(EX_RI_BAD_SIG1);
/* Not ADDing BAD_PORTS */
ADD(EX_RI_BAD_TOKENS);
@@ -903,7 +1405,7 @@ test_dir_load_routers(void *arg)
tt_int_op(smartlist_len(router_get_routerlist()->routers),OP_EQ,1);
routerinfo_t *r = smartlist_get(router_get_routerlist()->routers, 0);
test_memeq_hex(r->cache_info.signed_descriptor_digest,
- "581D8A368A0FA854ECDBFAB841D88B3F1B004038");
+ "1F437798ACD1FC9CBD1C3C04DBF80F7E9F819C3F");
tt_int_op(dls_minimal.n_download_failures, OP_EQ, 0);
tt_int_op(dls_maximal.n_download_failures, OP_EQ, 0);
@@ -916,13 +1418,12 @@ test_dir_load_routers(void *arg)
/* bad_sig2 and bad ports" are retriable -- one since only the signature
* was bad, and one because we didn't ask for it. */
- tt_int_op(dls_bad_sig2.n_download_failures, OP_EQ, 0);
+ tt_int_op(dls_bad_sig1.n_download_failures, OP_EQ, 0);
tt_int_op(dls_bad_ports.n_download_failures, OP_EQ, 0);
- /* Wanted still contains "BAD_SIG2" */
tt_int_op(smartlist_len(wanted), OP_EQ, 1);
tt_str_op(smartlist_get(wanted, 0), OP_EQ,
- "E0A3753CEFD54128EAB239F294954121DB23D2EF");
+ "3BB7D03C1C4DBC1DDE840096FF3C330914757B77");
#undef ADD
@@ -945,38 +1446,51 @@ static signed_descriptor_t sd_ei_maximal;
static signed_descriptor_t sd_ei_bad_tokens;
static signed_descriptor_t sd_ei_bad_sig2;
+static void
+setup_ei_digests(void)
+{
+#define SETUP(string, name) \
+ do { \
+ router_get_extrainfo_hash(string, strlen(string), \
+ (char*)digest_ei_##name); \
+ } while (0)
+
+ SETUP(EX_EI_MINIMAL, minimal);
+ SETUP(EX_EI_MAXIMAL, maximal);
+ SETUP(EX_EI_BAD_NICKNAME, bad_nickname);
+ SETUP(EX_EI_BAD_TOKENS, bad_tokens);
+ SETUP(EX_EI_BAD_SIG2, bad_sig2);
+ SETUP(EX_EI_BAD_PUBLISHED, bad_published);
+
+#undef SETUP
+}
+
static signed_descriptor_t *
mock_get_by_ei_desc_digest(const char *d)
{
-
++mock_get_by_ei_dd_calls;
- char hex[HEX_DIGEST_LEN+1];
- base16_encode(hex, sizeof(hex), d, DIGEST_LEN);
-
- if (!strcmp(hex, "11E0EDF526950739F7769810FCACAB8C882FAEEE")) {
- return &sd_ei_minimal;
- } else if (!strcmp(hex, "47803B02A0E70E9E8BDA226CB1D74DE354D67DFF")) {
- return &sd_ei_maximal;
- } else if (!strcmp(hex, "D5DF4AA62EE9FFC9543D41150C9864908E0390AF")) {
- return &sd_ei_bad_nickname;
- } else if (!strcmp(hex, "16D387D3A58F7DB3CF46638F8D0B90C45C7D769C")) {
- return &sd_ei_bad_sig2;
- } else if (!strcmp(hex, "9D90F8C42955BBC57D54FB05E54A3F083AF42E8B")) {
- return &sd_ei_bad_tokens;
- } else {
- ++mock_get_by_ei_dd_unrecognized;
- return NULL;
- }
+#define CHECK(name) \
+ do { \
+ if (fast_memeq(d, digest_ei_##name, DIGEST_LEN)) \
+ return &sd_ei_##name; \
+ } while (0)
+
+ CHECK(minimal);
+ CHECK(maximal);
+ CHECK(bad_nickname);
+ CHECK(bad_sig2);
+ CHECK(bad_tokens);
+ ++mock_get_by_ei_dd_unrecognized;
+ return NULL;
+#undef CHECK
}
static signed_descriptor_t *
mock_ei_get_by_ei_digest(const char *d)
{
- char hex[HEX_DIGEST_LEN+1];
- base16_encode(hex, sizeof(hex), d, DIGEST_LEN);
signed_descriptor_t *sd = &sd_ei_minimal;
- if (!strcmp(hex, "11E0EDF526950739F7769810FCACAB8C882FAEEE")) {
+ if (fast_memeq(d, digest_ei_minimal, DIGEST_LEN)) {
sd->signed_descriptor_body = (char *)EX_EI_MINIMAL;
sd->signed_descriptor_len = sizeof(EX_EI_MINIMAL);
sd->annotations_len = 0;
@@ -1012,6 +1526,7 @@ test_dir_load_extrainfo(void *arg)
smartlist_add_strdup(wanted, hex_str(buf, DIGEST_LEN)); \
} while (0)
+ setup_ei_digests();
mock_ei_insert_list = smartlist_new();
MOCK(router_get_by_extrainfo_digest, mock_get_by_ei_desc_digest);
MOCK(extrainfo_insert, mock_ei_insert);
@@ -1022,7 +1537,7 @@ test_dir_load_extrainfo(void *arg)
smartlist_add_strdup(chunks, EX_EI_BAD_PUBLISHED);
smartlist_add_strdup(chunks, EX_EI_BAD_TOKENS);
- /* not ADDing MINIMIAL */
+ /* not ADDing MINIMAL */
ADD(EX_EI_MAXIMAL);
ADD(EX_EI_BAD_NICKNAME);
/* Not ADDing BAD_PUBLISHED */
@@ -1038,12 +1553,12 @@ test_dir_load_extrainfo(void *arg)
tt_int_op(smartlist_len(mock_ei_insert_list),OP_EQ,2);
extrainfo_t *e = smartlist_get(mock_ei_insert_list, 0);
- test_memeq_hex(e->cache_info.signed_descriptor_digest,
- "11E0EDF526950739F7769810FCACAB8C882FAEEE");
+ tt_mem_op(e->cache_info.signed_descriptor_digest, OP_EQ,
+ digest_ei_minimal, DIGEST_LEN);
e = smartlist_get(mock_ei_insert_list, 1);
- test_memeq_hex(e->cache_info.signed_descriptor_digest,
- "47803B02A0E70E9E8BDA226CB1D74DE354D67DFF");
+ tt_mem_op(e->cache_info.signed_descriptor_digest, OP_EQ,
+ digest_ei_maximal, DIGEST_LEN);
tt_int_op(dls_minimal.n_download_failures, OP_EQ, 0);
tt_int_op(dls_maximal.n_download_failures, OP_EQ, 0);
@@ -1059,8 +1574,11 @@ test_dir_load_extrainfo(void *arg)
/* Wanted still contains "BAD_SIG2" */
tt_int_op(smartlist_len(wanted), OP_EQ, 1);
- tt_str_op(smartlist_get(wanted, 0), OP_EQ,
- "16D387D3A58F7DB3CF46638F8D0B90C45C7D769C");
+ const char *got_wanted =smartlist_get(wanted, 0);
+ tt_int_op(strlen(got_wanted), OP_EQ, HEX_DIGEST_LEN);
+ char d[DIGEST_LEN];
+ base16_decode(d, DIGEST_LEN, got_wanted, strlen(got_wanted));
+ tt_mem_op(d, OP_EQ, digest_ei_bad_sig2, DIGEST_LEN);
#undef ADD
@@ -1080,12 +1598,17 @@ test_dir_getinfo_extra(void *arg)
int r;
char *answer = NULL;
const char *errmsg = NULL;
-
+ char buf[128];
+ char hexdigest[HEX_DIGEST_LEN+1];
(void)arg;
+
+ setup_ei_digests();
+ base16_encode(hexdigest, sizeof(hexdigest),
+ (const char*)digest_ei_minimal, DIGEST_LEN);
+ tor_snprintf(buf, sizeof(buf), "extra-info/digest/%s", hexdigest);
+
MOCK(extrainfo_get_by_descriptor_digest, mock_ei_get_by_ei_digest);
- r = getinfo_helper_dir(NULL, "extra-info/digest/"
- "11E0EDF526950739F7769810FCACAB8C882FAEEE", &answer,
- &errmsg);
+ r = getinfo_helper_dir(NULL, buf, &answer, &errmsg);
tt_int_op(0, OP_EQ, r);
tt_ptr_op(NULL, OP_EQ, errmsg);
tt_str_op(answer, OP_EQ, EX_EI_MINIMAL);
@@ -1612,8 +2135,8 @@ test_dir_measured_bw_kb(void *arg)
/* Test that a line with vote=0 will fail too, so that it is ignored. */
"node_id=$557365204145532d32353620696e73746561642e bw=1024 vote=0\n",
/* Test that a line with vote=0 will fail even if unmeasured=0. */
- "node_id=$557365204145532d32353620696e73746561642e bw=1024 vote=0 "
- "unmeasured=0\n",
+ ("node_id=$557365204145532d32353620696e73746561642e bw=1024 vote=0 "
+ "unmeasured=0\n"),
"end"
};
@@ -1767,7 +2290,8 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, "", 0);
setup_capture_of_logs(LOG_WARN);
tt_int_op(-1, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
expect_log_msg("Empty bandwidth file\n");
teardown_capture_of_logs();
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
@@ -1783,7 +2307,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(-1, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op("", OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1794,7 +2320,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, header_lines_v100, 0);
bw_file_headers = smartlist_new();
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_v100, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1807,7 +2335,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_v100, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1818,7 +2348,8 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
tor_asprintf(&content, "%s%s", header_lines_v100, relay_lines_v100);
write_str_to_file(fname, content, 0);
tor_free(content);
- tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, NULL));
+ tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, NULL,
+ NULL));
/* Test bandwidth file including v1.1.0 bandwidth headers and
* v1.0.0 relay lines. bw_file_headers will contain the v1.1.0 headers. */
@@ -1828,7 +2359,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1844,7 +2377,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_v100, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1861,7 +2396,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_v100, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1872,7 +2409,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
bw_file_headers = smartlist_new();
write_str_to_file(fname, header_lines_v110_no_terminator, 0);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1883,7 +2422,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
bw_file_headers = smartlist_new();
write_str_to_file(fname, header_lines_v110, 0);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1898,7 +2439,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1913,7 +2456,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1929,7 +2474,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1946,7 +2493,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
tt_str_op(bw_file_headers_str_bad, OP_EQ, bw_file_headers_str);
SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c));
@@ -1964,7 +2513,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
tt_int_op(MAX_BW_FILE_HEADER_COUNT_IN_VOTE, OP_EQ,
smartlist_len(bw_file_headers));
bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL);
@@ -1985,7 +2536,9 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
write_str_to_file(fname, content, 0);
tor_free(content);
tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL,
- bw_file_headers));
+ bw_file_headers,
+ NULL));
+
tt_int_op(MAX_BW_FILE_HEADER_COUNT_IN_VOTE, OP_EQ,
smartlist_len(bw_file_headers));
/* force bw_file_headers to be bigger than
@@ -2014,7 +2567,8 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
/* Read the bandwidth file */
setup_full_capture_of_logs(LOG_DEBUG);
- tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, NULL));
+ tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, NULL,
+ NULL));
expect_log_msg_containing("Ignoring bandwidth file line");
teardown_capture_of_logs();
@@ -2032,11 +2586,13 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
/* Read the bandwidth file */
setup_full_capture_of_logs(LOG_DEBUG);
- tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, NULL));
+ tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, NULL,
+ NULL));
expect_log_msg_not_containing("Ignoring bandwidth file line");
teardown_capture_of_logs();
done:
+ unlink(fname);
tor_free(fname);
tor_free(header_lines_v100);
tor_free(header_lines_v110_no_terminator);
@@ -2274,6 +2830,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,
@@ -2291,7 +2848,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);
@@ -2299,7 +2856,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);
@@ -2307,8 +2864,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));
@@ -2328,9 +2886,9 @@ test_same_voter(networkstatus_voter_info_t *v1,
tt_str_op(v1->nickname,OP_EQ, v2->nickname);
tt_mem_op(v1->identity_digest,OP_EQ, v2->identity_digest, DIGEST_LEN);
tt_str_op(v1->address,OP_EQ, v2->address);
- tt_int_op(v1->addr,OP_EQ, v2->addr);
- tt_int_op(v1->dir_port,OP_EQ, v2->dir_port);
- tt_int_op(v1->or_port,OP_EQ, v2->or_port);
+ tt_assert(tor_addr_eq(&v1->ipv4_addr, &v2->ipv4_addr));
+ tt_int_op(v1->ipv4_dirport,OP_EQ, v2->ipv4_dirport);
+ tt_int_op(v1->ipv4_orport,OP_EQ, v2->ipv4_orport);
tt_str_op(v1->contact,OP_EQ, v2->contact);
tt_mem_op(v1->vote_digest,OP_EQ, v2->vote_digest, DIGEST_LEN);
done:
@@ -2420,9 +2978,9 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
"\x3\x3\x3\x3",
DIGEST_LEN);
tt_mem_op(rs->descriptor_digest,OP_EQ, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- tt_int_op(rs->addr,OP_EQ, 0x99008801);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 8000);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99008801));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 8000);
/* no flags except "running" (16) and "v2dir" (64) and "valid" (128) */
tt_u64_op(vrs->flags, OP_EQ, UINT64_C(0xd0));
} else if (tor_memeq(rs->identity_digest,
@@ -2442,9 +3000,9 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
tt_str_op(rs->nickname,OP_EQ, "router1");
}
tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- tt_int_op(rs->addr,OP_EQ, 0x99009901);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 0);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99009901));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
@@ -2536,9 +3094,9 @@ test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
tt_str_op(rs->nickname,OP_EQ, "router1");
tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
tt_int_op(rs->published_on,OP_EQ, now-1000);
- tt_int_op(rs->addr,OP_EQ, 0x99009901);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 0);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99009901));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
@@ -2863,17 +3421,23 @@ test_a_networkstatus(
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
/* Parse certificates and keys. */
- cert1 = mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
+ cert1 = mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1,
+ strlen(AUTHORITY_CERT_1),
+ NULL);
tt_assert(cert1);
- cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2, NULL);
+ cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2,
+ strlen(AUTHORITY_CERT_2),
+ NULL);
tt_assert(cert2);
- cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL);
+ cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3,
+ strlen(AUTHORITY_CERT_3),
+ NULL);
tt_assert(cert3);
sign_skey_1 = crypto_pk_new();
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,
@@ -2904,9 +3468,9 @@ test_a_networkstatus(
voter = smartlist_get(v1->voters, 0);
tt_str_op(voter->nickname,OP_EQ, "Voter1");
tt_str_op(voter->address,OP_EQ, "1.2.3.4");
- tt_int_op(voter->addr,OP_EQ, 0x01020304);
- tt_int_op(voter->dir_port,OP_EQ, 80);
- tt_int_op(voter->or_port,OP_EQ, 9000);
+ tt_assert(tor_addr_eq_ipv4h(&voter->ipv4_addr, 0x01020304));
+ tt_int_op(voter->ipv4_dirport,OP_EQ, 80);
+ tt_int_op(voter->ipv4_orport,OP_EQ, 9000);
tt_str_op(voter->contact,OP_EQ, "voter@example.com");
tt_assert(v1->cert);
tt_assert(!crypto_pk_cmp_keys(sign_skey_1, v1->cert->signing_key));
@@ -2969,7 +3533,7 @@ test_a_networkstatus(
sign_skey_leg1,
FLAV_NS);
tt_assert(consensus_text);
- con = networkstatus_parse_vote_from_string(consensus_text, NULL,
+ con = networkstatus_parse_vote_from_string_(consensus_text, NULL,
NS_TYPE_CONSENSUS);
tt_assert(con);
//log_notice(LD_GENERAL, "<<%s>>\n<<%s>>\n<<%s>>\n",
@@ -2981,7 +3545,7 @@ test_a_networkstatus(
sign_skey_leg1,
FLAV_MICRODESC);
tt_assert(consensus_text_md);
- con_md = networkstatus_parse_vote_from_string(consensus_text_md, NULL,
+ con_md = networkstatus_parse_vote_from_string_(consensus_text_md, NULL,
NS_TYPE_CONSENSUS);
tt_assert(con_md);
tt_int_op(con_md->flavor,OP_EQ, FLAV_MICRODESC);
@@ -3080,13 +3644,13 @@ test_a_networkstatus(
tt_assert(consensus_text3);
tt_assert(consensus_text_md2);
tt_assert(consensus_text_md3);
- con2 = networkstatus_parse_vote_from_string(consensus_text2, NULL,
+ con2 = networkstatus_parse_vote_from_string_(consensus_text2, NULL,
NS_TYPE_CONSENSUS);
- con3 = networkstatus_parse_vote_from_string(consensus_text3, NULL,
+ con3 = networkstatus_parse_vote_from_string_(consensus_text3, NULL,
NS_TYPE_CONSENSUS);
- con_md2 = networkstatus_parse_vote_from_string(consensus_text_md2, NULL,
+ con_md2 = networkstatus_parse_vote_from_string_(consensus_text_md2, NULL,
NS_TYPE_CONSENSUS);
- con_md3 = networkstatus_parse_vote_from_string(consensus_text_md3, NULL,
+ con_md3 = networkstatus_parse_vote_from_string_(consensus_text_md3, NULL,
NS_TYPE_CONSENSUS);
tt_assert(con2);
tt_assert(con3);
@@ -3408,9 +3972,9 @@ gen_routerstatus_for_umbw(int idx, time_t now)
strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
memset(rs->identity_digest, 3, DIGEST_LEN);
memset(rs->descriptor_digest, 78, DIGEST_LEN);
- rs->addr = 0x99008801;
- rs->or_port = 443;
- rs->dir_port = 8000;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0x99008801);
+ rs->ipv4_orport = 443;
+ rs->ipv4_dirport = 8000;
/* all flags but running and valid cleared */
rs->is_flagged_running = 1;
rs->is_valid = 1;
@@ -3422,6 +3986,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
vrs->has_measured_bw = 1;
rs->has_bandwidth = 1;
vrs->measured_bw_kb = rs->bandwidth_kb = max_unmeasured_bw_kb / 2;
+ vrs->protocols = tor_strdup("Link=2 Wombat=40");
break;
case 1:
/* Generate the second routerstatus. */
@@ -3432,9 +3997,9 @@ gen_routerstatus_for_umbw(int idx, time_t now)
strlcpy(rs->nickname, "router1", sizeof(rs->nickname));
memset(rs->identity_digest, 5, DIGEST_LEN);
memset(rs->descriptor_digest, 77, DIGEST_LEN);
- rs->addr = 0x99009901;
- rs->or_port = 443;
- rs->dir_port = 0;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0x99009901);
+ rs->ipv4_orport = 443;
+ rs->ipv4_dirport = 0;
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tor_addr_copy(&rs->ipv6_addr, &addr_ipv6);
rs->ipv6_orport = 4711;
@@ -3448,6 +4013,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
vrs->has_measured_bw = 1;
rs->has_bandwidth = 1;
vrs->measured_bw_kb = rs->bandwidth_kb = 2 * max_unmeasured_bw_kb;
+ vrs->protocols = tor_strdup("Link=2 Wombat=40");
break;
case 2:
/* Generate the third routerstatus. */
@@ -3458,9 +4024,9 @@ gen_routerstatus_for_umbw(int idx, time_t now)
strlcpy(rs->nickname, "router3", sizeof(rs->nickname));
memset(rs->identity_digest, 0x33, DIGEST_LEN);
memset(rs->descriptor_digest, 79, DIGEST_LEN);
- rs->addr = 0xAA009901;
- rs->or_port = 400;
- rs->dir_port = 9999;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0xAA009901);
+ rs->ipv4_orport = 400;
+ rs->ipv4_dirport = 9999;
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
rs->is_flagged_running = rs->is_valid =
rs->is_possible_guard = 1;
@@ -3473,6 +4039,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
rs->has_bandwidth = 1;
vrs->measured_bw_kb = 0;
rs->bandwidth_kb = 2 * max_unmeasured_bw_kb;
+ vrs->protocols = tor_strdup("Link=2 Wombat=40");
break;
case 3:
/* Generate a fourth routerstatus that is not running. */
@@ -3483,9 +4050,9 @@ gen_routerstatus_for_umbw(int idx, time_t now)
strlcpy(rs->nickname, "router4", sizeof(rs->nickname));
memset(rs->identity_digest, 0x34, DIGEST_LEN);
memset(rs->descriptor_digest, 47, DIGEST_LEN);
- rs->addr = 0xC0000203;
- rs->or_port = 500;
- rs->dir_port = 1999;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0xC0000203);
+ rs->ipv4_orport = 500;
+ rs->ipv4_dirport = 1999;
/* all flags but running and valid cleared */
rs->is_flagged_running = 1;
rs->is_valid = 1;
@@ -3498,6 +4065,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
rs->has_bandwidth = 1;
vrs->measured_bw_kb = 0;
rs->bandwidth_kb = max_unmeasured_bw_kb / 2;
+ vrs->protocols = tor_strdup("Link=2 Wombat=40");
break;
case 4:
/* No more for this test; return NULL */
@@ -3585,9 +4153,9 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
DIGEST_LEN);
tt_mem_op(rs->descriptor_digest,OP_EQ, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- tt_int_op(rs->addr,OP_EQ, 0x99008801);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 8000);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99008801));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 8000);
tt_assert(rs->has_bandwidth);
tt_assert(vrs->has_measured_bw);
tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb / 2);
@@ -3609,9 +4177,9 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
DIGEST_LEN);
tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- tt_int_op(rs->addr,OP_EQ, 0x99009901);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 0);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99009901));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
@@ -3718,9 +4286,9 @@ test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
tt_str_op(rs->nickname,OP_EQ, "router1");
tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
tt_int_op(rs->published_on,OP_EQ, now-1000);
- tt_int_op(rs->addr,OP_EQ, 0x99009901);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 0);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99009901));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
@@ -3821,9 +4389,9 @@ test_dir_fmt_control_ns(void *arg)
strlcpy(rs.nickname, "TetsuoMilk", sizeof(rs.nickname));
memcpy(rs.identity_digest, "Stately, plump Buck ", DIGEST_LEN);
memcpy(rs.descriptor_digest, "Mulligan came up fro", DIGEST_LEN);
- rs.addr = 0x20304050;
- rs.or_port = 9001;
- rs.dir_port = 9002;
+ tor_addr_from_ipv4h(&rs.ipv4_addr, 0x20304050);
+ rs.ipv4_orport = 9001;
+ rs.ipv4_dirport = 9002;
rs.is_exit = 1;
rs.is_fast = 1;
rs.is_flagged_running = 1;
@@ -3864,6 +4432,62 @@ mock_get_options(void)
return mock_options;
}
+/**
+ * Test dirauth_get_b64_digest_bw_file.
+ * This function should be near the other bwauth functions, but it needs
+ * mock_get_options, that is only defined here.
+ */
+
+static void
+test_dir_bwauth_bw_file_digest256(void *arg)
+{
+ (void)arg;
+ const char *content =
+ "1541171221\n"
+ "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 "
+ "master_key_ed25519=YaqV4vbvPYKucElk297eVdNArDz9HtIwUoIeo0+cVIpQ "
+ "bw=760 nick=Test time=2018-05-08T16:13:26\n";
+
+ char *fname = tor_strdup(get_fname("V3BandwidthsFile"));
+ /* Initialize to a wrong digest. */
+ uint8_t digest[DIGEST256_LEN] = "01234567890123456789abcdefghijkl";
+
+ /* Digest of an empty string. Initialize to a wrong digest. */
+ char digest_empty_str[DIGEST256_LEN] = "01234567890123456789abcdefghijkl";
+ crypto_digest256(digest_empty_str, "", 0, DIGEST_SHA256);
+
+ /* Digest of the content. Initialize to a wrong digest. */
+ char digest_expected[DIGEST256_LEN] = "01234567890123456789abcdefghijkl";
+ crypto_digest256(digest_expected, content, strlen(content), DIGEST_SHA256);
+
+ /* When the bandwidth file can not be found. */
+ tt_int_op(-1, OP_EQ,
+ dirserv_read_measured_bandwidths(fname,
+ NULL, NULL, digest));
+ tt_mem_op(digest, OP_EQ, digest_empty_str, DIGEST256_LEN);
+
+ /* When there is a timestamp but it is too old. */
+ write_str_to_file(fname, content, 0);
+ tt_int_op(-1, OP_EQ,
+ dirserv_read_measured_bandwidths(fname,
+ NULL, NULL, digest));
+ /* The digest will be correct. */
+ tt_mem_op(digest, OP_EQ, digest_expected, DIGEST256_LEN);
+
+ update_approx_time(1541171221);
+
+ /* When there is a bandwidth file and it can be read. */
+ tt_int_op(0, OP_EQ,
+ dirserv_read_measured_bandwidths(fname,
+ NULL, NULL, digest));
+ tt_mem_op(digest, OP_EQ, digest_expected, DIGEST256_LEN);
+
+ done:
+ unlink(fname);
+ tor_free(fname);
+ update_approx_time(time(NULL));
+}
+
static void
reset_routerstatus(routerstatus_t *rs,
const char *hex_identity_digest,
@@ -3874,7 +4498,7 @@ reset_routerstatus(routerstatus_t *rs,
hex_identity_digest, HEX_DIGEST_LEN);
/* A zero address matches everything, so the address needs to be set.
* But the specific value is irrelevant. */
- rs->addr = ipv4_addr;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, ipv4_addr);
}
#define ROUTER_A_ID_STR "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
@@ -3900,10 +4524,13 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
(void)arg;
/* Init options */
+ dirauth_options_t *dirauth_options =
+ tor_malloc_zero(sizeof(dirauth_options_t));
+
mock_options = tor_malloc(sizeof(or_options_t));
reset_options(mock_options, &mock_get_options_calls);
-
MOCK(get_options, mock_get_options);
+ dirauth_set_options(dirauth_options);
/* Init routersets */
routerset_t *routerset_all = routerset_new();
@@ -3943,16 +4570,15 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check that "*" sets flags on all routers: Exit
* Check the flags aren't being confused with each other */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_all;
- mock_options->TestingDirAuthVoteExitIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteExit = routerset_all;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 2);
tt_uint_op(rs_a->is_exit, OP_EQ, 1);
tt_uint_op(rs_b->is_exit, OP_EQ, 1);
@@ -3965,18 +4591,17 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check that "*" sets flags on all routers: Guard & HSDir
* Cover the remaining flags in one test */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteGuard = routerset_all;
- mock_options->TestingDirAuthVoteGuardIsStrict = 0;
- mock_options->TestingDirAuthVoteHSDir = routerset_all;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_all;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_all;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 2);
tt_uint_op(rs_a->is_possible_guard, OP_EQ, 1);
tt_uint_op(rs_b->is_possible_guard, OP_EQ, 1);
@@ -3989,20 +4614,19 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check routerset A sets all flags on router A,
* but leaves router B unmodified */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_a;
- mock_options->TestingDirAuthVoteExitIsStrict = 0;
- mock_options->TestingDirAuthVoteGuard = routerset_a;
- mock_options->TestingDirAuthVoteGuardIsStrict = 0;
- mock_options->TestingDirAuthVoteHSDir = routerset_a;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteExit = routerset_a;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_a;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_a;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 2);
tt_uint_op(rs_a->is_exit, OP_EQ, 1);
tt_uint_op(rs_b->is_exit, OP_EQ, 0);
@@ -4013,21 +4637,21 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check routerset A unsets all flags on router B when Strict is set */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_a;
- mock_options->TestingDirAuthVoteExitIsStrict = 1;
- mock_options->TestingDirAuthVoteGuard = routerset_a;
- mock_options->TestingDirAuthVoteGuardIsStrict = 1;
- mock_options->TestingDirAuthVoteHSDir = routerset_a;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteExit = routerset_a;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_a;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_a;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 1;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
tt_uint_op(rs_b->is_exit, OP_EQ, 0);
tt_uint_op(rs_b->is_possible_guard, OP_EQ, 0);
@@ -4035,21 +4659,21 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check routerset A doesn't modify flags on router B without Strict set */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_a;
- mock_options->TestingDirAuthVoteExitIsStrict = 0;
- mock_options->TestingDirAuthVoteGuard = routerset_a;
- mock_options->TestingDirAuthVoteGuardIsStrict = 0;
- mock_options->TestingDirAuthVoteHSDir = routerset_a;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteExit = routerset_a;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_a;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_a;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 0;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
tt_uint_op(rs_b->is_exit, OP_EQ, 1);
tt_uint_op(rs_b->is_possible_guard, OP_EQ, 1);
@@ -4058,21 +4682,21 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check the empty routerset zeroes all flags
* on routers A & B with Strict set */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_none;
- mock_options->TestingDirAuthVoteExitIsStrict = 1;
- mock_options->TestingDirAuthVoteGuard = routerset_none;
- mock_options->TestingDirAuthVoteGuardIsStrict = 1;
- mock_options->TestingDirAuthVoteHSDir = routerset_none;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteExit = routerset_none;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_none;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 1;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_none;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 1;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
tt_uint_op(rs_b->is_exit, OP_EQ, 0);
tt_uint_op(rs_b->is_possible_guard, OP_EQ, 0);
@@ -4081,24 +4705,23 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
/* Check the empty routerset doesn't modify any flags
* on A or B without Strict set */
reset_options(mock_options, &mock_get_options_calls);
+ memset(dirauth_options, 0, sizeof(*dirauth_options));
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
- mock_options->TestingDirAuthVoteExit = routerset_none;
- mock_options->TestingDirAuthVoteExitIsStrict = 0;
- mock_options->TestingDirAuthVoteGuard = routerset_none;
- mock_options->TestingDirAuthVoteGuardIsStrict = 0;
- mock_options->TestingDirAuthVoteHSDir = routerset_none;
- mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteExit = routerset_none;
+ dirauth_options->TestingDirAuthVoteExitIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteGuard = routerset_none;
+ dirauth_options->TestingDirAuthVoteGuardIsStrict = 0;
+ dirauth_options->TestingDirAuthVoteHSDir = routerset_none;
+ dirauth_options->TestingDirAuthVoteHSDirIsStrict = 0;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_a);
- tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_int_op(mock_get_options_calls, OP_EQ, 2);
tt_uint_op(rs_a->is_exit, OP_EQ, 0);
tt_uint_op(rs_a->is_possible_guard, OP_EQ, 0);
@@ -4109,6 +4732,7 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
done:
tor_free(mock_options);
+ tor_free(dirauth_options);
mock_options = NULL;
UNMOCK(get_options);
@@ -4196,6 +4820,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));
@@ -4683,15 +5315,15 @@ test_dir_conn_purpose_to_string(void *data)
teardown_capture_of_logs();
}
-NS_DECL(int,
-public_server_mode, (const or_options_t *options));
+static int dir_tests_public_server_mode(const or_options_t *options);
+ATTR_UNUSED static int dir_tests_public_server_mode_called = 0;
static int
-NS(public_server_mode)(const or_options_t *options)
+dir_tests_public_server_mode(const or_options_t *options)
{
(void)options;
- if (CALLED(public_server_mode)++ == 0) {
+ if (dir_tests_public_server_mode_called++ == 0) {
return 1;
}
@@ -4705,13 +5337,14 @@ test_dir_should_use_directory_guards(void *data)
char *errmsg = NULL;
(void)data;
- NS_MOCK(public_server_mode);
+ MOCK(public_server_mode,
+ dir_tests_public_server_mode);
options = options_new();
options_init(options);
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 1);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 1);
options->UseEntryGuards = 1;
options->DownloadExtraInfo = 0;
@@ -4719,41 +5352,41 @@ test_dir_should_use_directory_guards(void *data)
options->FetchDirInfoExtraEarly = 0;
options->FetchUselessDescriptors = 0;
tt_int_op(should_use_directory_guards(options), OP_EQ, 1);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 2);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 2);
options->UseEntryGuards = 0;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 3);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 3);
options->UseEntryGuards = 1;
options->DownloadExtraInfo = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 4);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 4);
options->DownloadExtraInfo = 0;
options->FetchDirInfoEarly = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 5);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 5);
options->FetchDirInfoEarly = 0;
options->FetchDirInfoExtraEarly = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 6);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 6);
options->FetchDirInfoExtraEarly = 0;
options->FetchUselessDescriptors = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 7);
+ tt_int_op(dir_tests_public_server_mode_called, OP_EQ, 7);
options->FetchUselessDescriptors = 0;
done:
- NS_UNMOCK(public_server_mode);
+ UNMOCK(public_server_mode);
or_options_free(options);
tor_free(errmsg);
}
-NS_DECL(void,
-directory_initiate_request, (directory_request_t *req));
+static void dir_tests_directory_initiate_request(directory_request_t *req);
+ATTR_UNUSED static int dir_tests_directory_initiate_request_called = 0;
static void
test_dir_should_not_init_request_to_ourselves(void *data)
@@ -4763,7 +5396,8 @@ test_dir_should_not_init_request_to_ourselves(void *data)
crypto_pk_t *key = pk_generate(2);
(void) data;
- NS_MOCK(directory_initiate_request);
+ MOCK(directory_initiate_request,
+ dir_tests_directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
@@ -4778,15 +5412,15 @@ test_dir_should_not_init_request_to_ourselves(void *data)
dir_server_add(ourself);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 0);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0,
NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 0);
done:
- NS_UNMOCK(directory_initiate_request);
+ UNMOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
crypto_pk_free(key);
@@ -4800,7 +5434,8 @@ test_dir_should_not_init_request_to_dir_auths_without_v3_info(void *data)
| MICRODESC_DIRINFO;
(void) data;
- NS_MOCK(directory_initiate_request);
+ MOCK(directory_initiate_request,
+ dir_tests_directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
@@ -4811,14 +5446,14 @@ test_dir_should_not_init_request_to_dir_auths_without_v3_info(void *data)
dir_server_add(ds);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 0);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0,
NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 0);
done:
- NS_UNMOCK(directory_initiate_request);
+ UNMOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
}
@@ -4829,7 +5464,8 @@ test_dir_should_init_request_to_dir_auths(void *data)
dir_server_t *ds = NULL;
(void) data;
- NS_MOCK(directory_initiate_request);
+ MOCK(directory_initiate_request,
+ dir_tests_directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
@@ -4840,23 +5476,23 @@ test_dir_should_init_request_to_dir_auths(void *data)
dir_server_add(ds);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 1);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 1);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0,
NULL);
- tt_int_op(CALLED(directory_initiate_request), OP_EQ, 2);
+ tt_int_op(dir_tests_directory_initiate_request_called, OP_EQ, 2);
done:
- NS_UNMOCK(directory_initiate_request);
+ UNMOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
}
void
-NS(directory_initiate_request)(directory_request_t *req)
+dir_tests_directory_initiate_request(directory_request_t *req)
{
(void)req;
- CALLED(directory_initiate_request)++;
+ dir_tests_directory_initiate_request_called++;
}
/*
@@ -6062,6 +6698,82 @@ test_dir_find_dl_min_delay(void* data)
}
static void
+test_dir_matching_flags(void *arg)
+{
+ (void) arg;
+ routerstatus_t *rs_noflags = NULL;
+ routerstatus_t *rs = NULL;
+ char *s = NULL;
+
+ smartlist_t *tokens = smartlist_new();
+ memarea_t *area = memarea_new();
+
+ int expected_val_when_unused = 0;
+
+ const char *ex_noflags =
+ "r example hereiswhereyouridentitygoes 2015-08-30 12:00:00 "
+ "192.168.0.1 9001 0\n"
+ "m thisoneislongerbecauseitisa256bitmddigest33\n"
+ "s\n"
+ "pr Link=4\n";
+ const char *cp = ex_noflags;
+ rs_noflags = routerstatus_parse_entry_from_string(
+ area, &cp,
+ cp + strlen(cp),
+ tokens, NULL, NULL,
+ MAX_SUPPORTED_CONSENSUS_METHOD, FLAV_MICRODESC);
+ tt_assert(rs_noflags);
+
+#define FLAG(string, field) STMT_BEGIN { \
+ tor_asprintf(&s,\
+ "r example hereiswhereyouridentitygoes 2015-08-30 12:00:00 " \
+ "192.168.0.1 9001 0\n" \
+ "m thisoneislongerbecauseitisa256bitmddigest33\n" \
+ "pr Link=4\n" \
+ "s %s\n", string); \
+ cp = s; \
+ rs = routerstatus_parse_entry_from_string( \
+ area, &cp, \
+ cp + strlen(cp), \
+ tokens, NULL, NULL, \
+ MAX_SUPPORTED_CONSENSUS_METHOD, FLAV_MICRODESC); \
+ /* the field should usually be 0 when no flags are listed */ \
+ tt_int_op(rs_noflags->field, OP_EQ, expected_val_when_unused); \
+ /* the field should be 1 when this flags islisted */ \
+ tt_int_op(rs->field, OP_EQ, 1); \
+ tor_free(s); \
+ routerstatus_free(rs); \
+} STMT_END
+
+ FLAG("Authority", is_authority);
+ FLAG("BadExit", is_bad_exit);
+ FLAG("Exit", is_exit);
+ FLAG("Fast", is_fast);
+ FLAG("Guard", is_possible_guard);
+ FLAG("HSDir", is_hs_dir);
+ FLAG("Stable", is_stable);
+ FLAG("StaleDesc", is_staledesc);
+ FLAG("V2Dir", is_v2_dir);
+
+ // These flags are assumed to be set whether they're declared or not.
+ expected_val_when_unused = 1;
+ FLAG("Running", is_flagged_running);
+ FLAG("Valid", is_valid);
+ expected_val_when_unused = 0;
+
+ // These flags are no longer used, but still parsed.
+ FLAG("Named", is_named);
+ FLAG("Unnamed", is_unnamed);
+
+ done:
+ tor_free(s);
+ routerstatus_free(rs);
+ routerstatus_free(rs_noflags);
+ memarea_drop_all(area);
+ smartlist_free(tokens);
+}
+
+static void
test_dir_assumed_flags(void *arg)
{
(void)arg;
@@ -6075,10 +6787,12 @@ test_dir_assumed_flags(void *arg)
"r example hereiswhereyouridentitygoes 2015-08-30 12:00:00 "
"192.168.0.1 9001 0\n"
"m thisoneislongerbecauseitisa256bitmddigest33\n"
- "s Fast Guard Stable\n";
+ "s Fast Guard Stable\n"
+ "pr Link=4\n";
+ const char *eos = str1 + strlen(str1);
const char *cp = str1;
- rs = routerstatus_parse_entry_from_string(area, &cp, tokens, NULL, NULL,
+ rs = routerstatus_parse_entry_from_string(area, &cp, eos, tokens, NULL, NULL,
24, FLAV_MICRODESC);
tt_assert(rs);
tt_assert(rs->is_flagged_running);
@@ -6176,98 +6890,6 @@ test_dir_platform_str(void *arg)
;
}
-static networkstatus_t *mock_networkstatus;
-
-static networkstatus_t *
-mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
-{
- (void)f;
- return mock_networkstatus;
-}
-
-static void
-test_dir_networkstatus_consensus_has_ipv6(void *arg)
-{
- (void)arg;
-
- int has_ipv6 = 0;
-
- /* Init options and networkstatus */
- or_options_t our_options;
- mock_options = &our_options;
- reset_options(mock_options, &mock_get_options_calls);
- MOCK(get_options, mock_get_options);
-
- networkstatus_t our_networkstatus;
- mock_networkstatus = &our_networkstatus;
- memset(mock_networkstatus, 0, sizeof(*mock_networkstatus));
- MOCK(networkstatus_get_latest_consensus_by_flavor,
- mock_networkstatus_get_latest_consensus_by_flavor);
-
- /* A live consensus */
- mock_networkstatus->valid_after = time(NULL) - 3600;
- mock_networkstatus->valid_until = time(NULL) + 3600;
-
- /* Test the bounds for A lines in the NS consensus */
- mock_options->UseMicrodescriptors = 0;
-
- mock_networkstatus->consensus_method = MIN_SUPPORTED_CONSENSUS_METHOD;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- /* Test the bounds for A lines in the microdesc consensus */
- mock_options->UseMicrodescriptors = 1;
-
- mock_networkstatus->consensus_method =
- MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- mock_networkstatus->consensus_method = MAX_SUPPORTED_CONSENSUS_METHOD + 20;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- mock_networkstatus->consensus_method =
- MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS + 1;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- mock_networkstatus->consensus_method =
- MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS + 20;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- mock_networkstatus->consensus_method =
- MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS - 1;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(!has_ipv6);
-
- /* Test the edge cases */
- mock_options->UseMicrodescriptors = 1;
- mock_networkstatus->consensus_method =
- MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS;
-
- /* Reasonably live */
- mock_networkstatus->valid_until = approx_time() - 60;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(has_ipv6);
-
- /* Not reasonably live */
- mock_networkstatus->valid_after = approx_time() - 24*60*60 - 3600;
- mock_networkstatus->valid_until = approx_time() - 24*60*60 - 60;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(!has_ipv6);
-
- /* NULL consensus */
- mock_networkstatus = NULL;
- has_ipv6 = networkstatus_consensus_has_ipv6(get_options());
- tt_assert(!has_ipv6);
-
- done:
- UNMOCK(get_options);
- UNMOCK(networkstatus_get_latest_consensus_by_flavor);
-}
-
static void
test_dir_format_versions_list(void *arg)
{
@@ -6319,6 +6941,301 @@ test_dir_format_versions_list(void *arg)
teardown_capture_of_logs();
}
+static void
+test_dir_add_fingerprint(void *arg)
+{
+ (void)arg;
+ authdir_config_t *list;
+ int ret;
+ ed25519_secret_key_t seckey;
+ ed25519_public_key_t pubkey_good, pubkey_bad;
+
+ authdir_init_fingerprint_list();
+ list = authdir_return_fingerprint_list();
+
+ setup_capture_of_logs(LOG_WARN);
+
+ /* RSA test - successful */
+ ret = add_rsa_fingerprint_to_dir("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ list, 0);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* RSA test - failure */
+ ret = add_rsa_fingerprint_to_dir("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
+ list, 0);
+ tt_int_op(ret, OP_EQ, -1);
+
+ /* ed25519 test - successful */
+ ed25519_secret_key_generate(&seckey, 0);
+ ed25519_public_key_generate(&pubkey_good, &seckey);
+
+ ret = add_ed25519_to_dir(&pubkey_good, list, 0);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* ed25519 test - failure */
+ digest256_from_base64((char *) pubkey_bad.pubkey, "gibberish");
+
+ ret = add_ed25519_to_dir(&pubkey_bad, list, 0);
+ tt_int_op(ret, OP_EQ, -1);
+
+ done:
+ teardown_capture_of_logs();
+ dirserv_free_fingerprint_list();
+}
+
+static void
+test_dir_dirserv_load_fingerprint_file(void *arg)
+{
+ (void)arg;
+ char *fname = tor_strdup(get_fname("approved-routers"));
+
+ // Neither RSA nor ed25519
+ const char *router_lines_invalid =
+ "!badexit notafingerprint";
+ const char *router_lines_too_long =
+ "!badexit thisisareallylongstringthatislongerthanafingerprint\n";
+ const char *router_lines_bad_fmt_str =
+ "!badexit ABCDEFGH|%1$p|%2$p|%3$p|%4$p|%5$p|%6$p\n";
+ const char *router_lines_valid_rsa =
+ "!badexit AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n";
+ const char *router_lines_invalid_rsa =
+ "!badexit ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\n";
+ const char *router_lines_valid_ed25519 =
+ "!badexit wqfLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx/Q\n";
+ const char *router_lines_invalid_ed25519 =
+ "!badexit --fLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx--\n";
+
+ // Test: Invalid Fingerprint (not RSA or ed25519)
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_invalid, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ expect_log_msg_containing("Invalid fingerprint");
+ teardown_capture_of_logs();
+
+ // Test: Very long string (longer than RSA or ed25519 key)
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_too_long, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ expect_log_msg_containing("Invalid fingerprint");
+ teardown_capture_of_logs();
+
+ // Test: Format string exploit
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_bad_fmt_str, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ expect_log_msg_containing("Invalid fingerprint");
+ teardown_capture_of_logs();
+
+ // Test: Valid RSA
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_valid_rsa, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ teardown_capture_of_logs();
+
+ // Test: Invalid RSA
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_invalid_rsa, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ expect_log_msg_containing("Invalid fingerprint");
+ teardown_capture_of_logs();
+
+ // Test: Valid ed25519
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_valid_ed25519, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ teardown_capture_of_logs();
+
+ // Test: Invalid ed25519
+ setup_capture_of_logs(LOG_NOTICE);
+ write_str_to_file(fname, router_lines_invalid_ed25519, 0);
+ tt_int_op(dirserv_load_fingerprint_file(), OP_EQ, 0);
+ expect_log_msg_containing("Invalid fingerprint");
+ teardown_capture_of_logs();
+
+ done:
+ tor_free(fname);
+ dirserv_free_fingerprint_list();
+}
+
+#define RESET_FP_LIST(list) STMT_BEGIN \
+ dirserv_free_fingerprint_list(); \
+ authdir_init_fingerprint_list(); \
+ list = authdir_return_fingerprint_list(); \
+ STMT_END
+
+static void
+test_dir_dirserv_router_get_status(void *arg)
+{
+ authdir_config_t *list;
+ routerinfo_t *ri = NULL;
+ ed25519_keypair_t kp1, kp2;
+ char d[DIGEST_LEN];
+ char fp[HEX_DIGEST_LEN+1];
+ int ret;
+ const char *msg;
+ time_t now = time(NULL);
+
+ (void)arg;
+
+ crypto_pk_t *pk = pk_generate(0);
+
+ authdir_init_fingerprint_list();
+ list = authdir_return_fingerprint_list();
+
+ /* Set up the routerinfo */
+ ri = tor_malloc_zero(sizeof(routerinfo_t));
+ tor_addr_from_ipv4h(&ri->ipv4_addr, 0xc0a80001u);
+ ri->ipv4_orport = 9001;
+ ri->platform = tor_strdup("0.4.0.1-alpha");
+ ri->nickname = tor_strdup("Jessica");
+ ri->identity_pkey = crypto_pk_dup_key(pk);
+
+ curve25519_keypair_t ri_onion_keypair;
+ curve25519_keypair_generate(&ri_onion_keypair, 0);
+ ri->onion_curve25519_pkey = tor_memdup(&ri_onion_keypair.pubkey,
+ sizeof(curve25519_public_key_t));
+
+ ed25519_secret_key_from_seed(&kp1.seckey,
+ (const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
+ ed25519_public_key_generate(&kp1.pubkey, &kp1.seckey);
+ ed25519_secret_key_from_seed(&kp2.seckey,
+ (const uint8_t*)"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ ed25519_public_key_generate(&kp2.pubkey, &kp2.seckey);
+ ri->cache_info.signing_key_cert = tor_cert_create_ed25519(&kp1,
+ CERT_TYPE_ID_SIGNING,
+ &kp2.pubkey,
+ now, 86400,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+
+ crypto_pk_get_digest(ri->identity_pkey, d);
+ base16_encode(fp, HEX_DIGEST_LEN + 1, d, DIGEST_LEN);
+
+ /* Try on an empty fingerprint list */
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, 0);
+ RESET_FP_LIST(list);
+
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, 0);
+ RESET_FP_LIST(list);
+
+ /* Try an accepted router */
+ add_rsa_fingerprint_to_dir(fp, list, 0);
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, 0);
+ RESET_FP_LIST(list);
+
+ add_ed25519_to_dir(&kp1.pubkey, list, 0);
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, 0);
+ RESET_FP_LIST(list);
+
+ /* Try a rejected router */
+ add_rsa_fingerprint_to_dir(fp, list, RTR_REJECT);
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, RTR_REJECT);
+ RESET_FP_LIST(list);
+
+ add_ed25519_to_dir(&kp1.pubkey, list, RTR_REJECT);
+ ret = dirserv_router_get_status(ri, &msg, LOG_INFO);
+ tt_int_op(ret, OP_EQ, RTR_REJECT);
+ RESET_FP_LIST(list);
+
+ done:
+ dirserv_free_fingerprint_list();
+ routerinfo_free(ri);
+ crypto_pk_free(pk);
+}
+
+static void
+test_dir_dirserv_would_reject_router(void *arg)
+{
+ authdir_config_t *list;
+ routerstatus_t rs;
+ vote_routerstatus_t vrs;
+ ed25519_keypair_t kp;
+ char fp[HEX_DIGEST_LEN+1];
+
+ (void)arg;
+
+ authdir_init_fingerprint_list();
+ list = authdir_return_fingerprint_list();
+
+ /* Set up the routerstatus */
+ memset(&rs, 0, sizeof(rs));
+ tor_addr_from_ipv4h(&rs.ipv4_addr, 0xc0a80001u);
+ rs.ipv4_orport = 9001;
+ strlcpy(rs.nickname, "Nicole", sizeof(rs.nickname));
+ memcpy(rs.identity_digest, "Cloud nine is great ", DIGEST_LEN);
+
+ ed25519_secret_key_from_seed(&kp.seckey,
+ (const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
+ ed25519_public_key_generate(&kp.pubkey, &kp.seckey);
+
+ base16_encode(fp, HEX_DIGEST_LEN + 1, rs.identity_digest, DIGEST_LEN);
+
+ /* Setup the vote_routerstatus_t. */
+ memcpy(vrs.ed25519_id, &kp.pubkey, ED25519_PUBKEY_LEN);
+
+ /* Try an empty fingerprint list */
+ tt_assert(!dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ tt_assert(!dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ /* Try an accepted router */
+ add_rsa_fingerprint_to_dir(fp, list, 0);
+ tt_assert(!dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ add_ed25519_to_dir(&kp.pubkey, list, 0);
+ tt_assert(!dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ /* Try a rejected router */
+ add_rsa_fingerprint_to_dir(fp, list, RTR_REJECT);
+ tt_assert(dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ add_ed25519_to_dir(&kp.pubkey, list, RTR_REJECT);
+ tt_assert(dirserv_would_reject_router(&rs, &vrs));
+ RESET_FP_LIST(list);
+
+ done:
+ dirserv_free_fingerprint_list();
+}
+
+static void
+test_dir_dirserv_add_own_fingerprint(void *arg)
+{
+ authdir_config_t *list;
+ char digest[DIGEST_LEN];
+ crypto_pk_t *pk = pk_generate(0);
+
+ (void)arg;
+
+ init_mock_ed_keys(pk);
+ authdir_init_fingerprint_list();
+ list = authdir_return_fingerprint_list();
+ dirserv_add_own_fingerprint(pk, get_master_identity_key());
+
+ /* Check if we have a RSA key. */
+ crypto_pk_get_digest(pk, digest);
+ tt_assert(digestmap_get(list->status_by_digest, digest));
+
+ /* Check if we have a ed25519 key. */
+ tt_assert(digest256map_get(list->status_by_digest256,
+ get_master_identity_key()->pubkey));
+
+ RESET_FP_LIST(list);
+
+ done:
+ dirserv_free_fingerprint_list();
+ crypto_pk_free(pk);
+}
+
+#ifndef COCCI
#define DIR_LEGACY(name) \
{ #name, test_dir_ ## name , TT_FORK, NULL, NULL }
@@ -6328,10 +7245,20 @@ test_dir_format_versions_list(void *arg)
/* where arg is a string constant */
#define DIR_ARG(name,flags,arg) \
{ #name "_" arg, test_dir_##name, (flags), &passthrough_setup, (void*) arg }
+#endif /* !defined(COCCI) */
struct testcase_t dir_tests[] = {
DIR_LEGACY(nicknames),
- DIR_LEGACY(formats),
+ /* extrainfo without any stats */
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, ""),
+ /* on a bridge */
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, "b"),
+ /* extrainfo with basic stats */
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, "e"),
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, "be"),
+ /* extrainfo with all stats */
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, "es"),
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, "bes"),
DIR(routerinfo_parsing, 0),
DIR(extrainfo_parsing, 0),
DIR(parse_router_list, TT_FORK),
@@ -6345,6 +7272,7 @@ struct testcase_t dir_tests[] = {
DIR_LEGACY(measured_bw_kb_line_is_after_headers),
DIR_LEGACY(measured_bw_kb_cache),
DIR_LEGACY(dirserv_read_measured_bandwidths),
+ DIR(bwauth_bw_file_digest256, 0),
DIR_LEGACY(param_voting),
DIR(param_voting_lookup, 0),
DIR_LEGACY(v3_networkstatus),
@@ -6353,7 +7281,7 @@ struct testcase_t dir_tests[] = {
DIR_LEGACY(clip_unmeasured_bw_kb),
DIR_LEGACY(clip_unmeasured_bw_kb_alt),
DIR(fmt_control_ns, 0),
- DIR(dirserv_set_routerstatus_testing, 0),
+ DIR(dirserv_set_routerstatus_testing, TT_FORK),
DIR(http_handling, 0),
DIR(purpose_needs_anonymity_returns_true_for_bridges, 0),
DIR(purpose_needs_anonymity_returns_false_for_own_bridge_desc, 0),
@@ -6384,9 +7312,14 @@ struct testcase_t dir_tests[] = {
DIR_ARG(find_dl_min_delay, TT_FORK, "cfr"),
DIR_ARG(find_dl_min_delay, TT_FORK, "car"),
DIR(assumed_flags, 0),
+ DIR(matching_flags, 0),
DIR(networkstatus_compute_bw_weights_v10, 0),
DIR(platform_str, 0),
- DIR(networkstatus_consensus_has_ipv6, TT_FORK),
DIR(format_versions_list, TT_FORK),
+ DIR(add_fingerprint, TT_FORK),
+ DIR(dirserv_load_fingerprint_file, TT_FORK),
+ DIR(dirserv_router_get_status, TT_FORK),
+ DIR(dirserv_would_reject_router, TT_FORK),
+ DIR(dirserv_add_own_fingerprint, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index 3723d6c31b..77e3851183 100644
--- a/src/test/test_dir_common.c
+++ b/src/test/test_dir_common.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -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"
@@ -42,14 +42,20 @@ dir_common_authority_pk_init(authority_cert_t **cert1,
{
/* Parse certificates and keys. */
authority_cert_t *cert;
- cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
+ cert = authority_cert_parse_from_string(AUTHORITY_CERT_1,
+ strlen(AUTHORITY_CERT_1),
+ NULL);
tt_assert(cert);
tt_assert(cert->identity_key);
*cert1 = cert;
tt_assert(*cert1);
- *cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2, NULL);
+ *cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2,
+ strlen(AUTHORITY_CERT_2),
+ NULL);
tt_assert(*cert2);
- *cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL);
+ *cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3,
+ strlen(AUTHORITY_CERT_3),
+ NULL);
tt_assert(*cert3);
*sign_skey_1 = crypto_pk_new();
*sign_skey_2 = crypto_pk_new();
@@ -91,13 +97,14 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
memset(rs->identity_digest, TEST_DIR_ROUTER_ID_1, DIGEST_LEN);
memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_1, DIGEST_LEN);
- rs->addr = 0x99008801;
- rs->or_port = 443;
- rs->dir_port = 8000;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0x99008801);
+ rs->ipv4_orport = 443;
+ rs->ipv4_dirport = 8000;
/* all flags but running and v2dir cleared */
rs->is_flagged_running = 1;
rs->is_v2_dir = 1;
rs->is_valid = 1; /* xxxxx */
+ vrs->protocols = tor_strdup("Link=7 HSDir=3");
break;
case 1:
/* Generate the second routerstatus. */
@@ -108,14 +115,15 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
strlcpy(rs->nickname, "router1", sizeof(rs->nickname));
memset(rs->identity_digest, TEST_DIR_ROUTER_ID_2, DIGEST_LEN);
memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_2, DIGEST_LEN);
- rs->addr = 0x99009901;
- rs->or_port = 443;
- rs->dir_port = 0;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0x99009901);
+ rs->ipv4_orport = 443;
+ rs->ipv4_dirport = 0;
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tor_addr_copy(&rs->ipv6_addr, &addr_ipv6);
rs->ipv6_orport = 4711;
rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running =
rs->is_valid = rs->is_possible_guard = rs->is_v2_dir = 1;
+ vrs->protocols = tor_strdup("Link=3,4 HSDir=2,3");
break;
case 2:
/* Generate the third routerstatus. */
@@ -126,12 +134,13 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
strlcpy(rs->nickname, "router3", sizeof(rs->nickname));
memset(rs->identity_digest, TEST_DIR_ROUTER_ID_3, DIGEST_LEN);
memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_3, DIGEST_LEN);
- rs->addr = 0xAA009901;
- rs->or_port = 400;
- rs->dir_port = 9999;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0xAA009901);
+ rs->ipv4_orport = 400;
+ rs->ipv4_dirport = 9999;
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
rs->is_flagged_running = rs->is_valid = rs->is_v2_dir =
rs->is_possible_guard = 1;
+ vrs->protocols = tor_strdup("Link=3,4 HSDir=2,3");
break;
case 3:
/* Generate a fourth routerstatus that is not running. */
@@ -142,10 +151,11 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
strlcpy(rs->nickname, "router4", sizeof(rs->nickname));
memset(rs->identity_digest, TEST_DIR_ROUTER_ID_4, DIGEST_LEN);
memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_4, DIGEST_LEN);
- rs->addr = 0xC0000203;
- rs->or_port = 500;
- rs->dir_port = 1999;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0xC0000203);
+ rs->ipv4_orport = 500;
+ rs->ipv4_dirport = 1999;
rs->is_v2_dir = 1;
+ vrs->protocols = tor_strdup("Link=3,4 HSDir=3");
/* Running flag (and others) cleared */
break;
case 4:
@@ -266,7 +276,9 @@ dir_common_add_rs_and_parse(networkstatus_t *vote, networkstatus_t **vote_out,
/* dump the vote and try to parse it. */
v_text = format_networkstatus_vote(sign_skey, vote);
tt_assert(v_text);
- *vote_out = networkstatus_parse_vote_from_string(v_text, NULL, NS_TYPE_VOTE);
+ *vote_out = networkstatus_parse_vote_from_string(v_text,
+ strlen(v_text),
+ NULL, NS_TYPE_VOTE);
done:
if (v_text)
@@ -305,9 +317,9 @@ dir_common_construct_vote_1(networkstatus_t **vote, authority_cert_t *cert,
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
voter->nickname = tor_strdup("Voter1");
voter->address = tor_strdup("1.2.3.4");
- voter->addr = 0x01020304;
- voter->dir_port = 80;
- voter->or_port = 9000;
+ tor_addr_from_ipv4h(&voter->ipv4_addr, 0x01020304);
+ voter->ipv4_dirport = 80;
+ voter->ipv4_orport = 9000;
voter->contact = tor_strdup("voter@example.com");
crypto_pk_get_digest(cert->identity_key, voter->identity_digest);
/*
@@ -354,9 +366,9 @@ dir_common_construct_vote_2(networkstatus_t **vote, authority_cert_t *cert,
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
voter->nickname = tor_strdup("Voter2");
voter->address = tor_strdup("2.3.4.5");
- voter->addr = 0x02030405;
- voter->dir_port = 80;
- voter->or_port = 9000;
+ tor_addr_from_ipv4h(&voter->ipv4_addr, 0x02030405);
+ voter->ipv4_dirport = 80;
+ voter->ipv4_orport = 9000;
voter->contact = tor_strdup("voter@example.com");
crypto_pk_get_digest(cert->identity_key, voter->identity_digest);
/*
@@ -404,9 +416,9 @@ dir_common_construct_vote_3(networkstatus_t **vote, authority_cert_t *cert,
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
voter->nickname = tor_strdup("Voter2");
voter->address = tor_strdup("3.4.5.6");
- voter->addr = 0x03040506;
- voter->dir_port = 80;
- voter->or_port = 9000;
+ tor_addr_from_ipv4h(&voter->ipv4_addr, 0x03040506);
+ voter->ipv4_dirport = 80;
+ voter->ipv4_orport = 9000;
voter->contact = tor_strdup("voter@example.com");
crypto_pk_get_digest(cert->identity_key, voter->identity_digest);
memset(voter->legacy_id_digest, (int)'A', DIGEST_LEN);
@@ -424,4 +436,3 @@ dir_common_construct_vote_3(networkstatus_t **vote, authority_cert_t *cert,
return 0;
}
-
diff --git a/src/test/test_dir_common.h b/src/test/test_dir_common.h
index d6c5241b14..d37496465c 100644
--- a/src/test/test_dir_common.h
+++ b/src/test/test_dir_common.h
@@ -1,8 +1,11 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#ifndef TOR_TEST_DIR_COMMON_H
+#define TOR_TEST_DIR_COMMON_H
+
#include "core/or/or.h"
#include "feature/nodelist/networkstatus.h"
@@ -49,3 +52,4 @@ int dir_common_construct_vote_3(networkstatus_t **vote,
networkstatus_t **vote_out, int *n_vrs, time_t now,
int clear_rl);
+#endif /* !defined(TOR_TEST_DIR_COMMON_H) */
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index e71bcb9eb2..95339160c3 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define RENDCOMMON_PRIVATE
@@ -20,6 +20,7 @@
#include "lib/compress/compress.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendcache.h"
+#include "feature/relay/relay_config.h"
#include "feature/relay/router.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
@@ -30,6 +31,7 @@
#include "feature/nodelist/nodelist.h"
#include "feature/client/entrynodes.h"
#include "feature/dirparse/authcert_parse.h"
+#include "feature/dirparse/sigcommon.h"
#include "feature/nodelist/networkstatus.h"
#include "core/proto/proto_http.h"
#include "lib/geoip/geoip.h"
@@ -37,7 +39,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"
@@ -54,17 +56,15 @@
#endif /* defined(_WIN32) */
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-DISABLE_GCC_WARNING(overlength-strings)
+DISABLE_GCC_WARNING("-Woverlength-strings")
/* We allow huge string constants in the unit tests, but not in the code
* at large. */
#endif
#include "vote_descriptors.inc"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-ENABLE_GCC_WARNING(overlength-strings)
+ENABLE_GCC_WARNING("-Woverlength-strings")
#endif
-#define NS_MODULE dir_handle_get
-
#define NOT_FOUND "HTTP/1.0 404 Not found\r\n\r\n"
#define BAD_REQUEST "HTTP/1.0 400 Bad request\r\n\r\n"
#define SERVER_BUSY "HTTP/1.0 503 Directory busy, try again later\r\n\r\n"
@@ -72,6 +72,25 @@ ENABLE_GCC_WARNING(overlength-strings)
#define NOT_ENOUGH_CONSENSUS_SIGNATURES "HTTP/1.0 404 " \
"Consensus not signed by sufficient number of requested authorities\r\n\r\n"
+#define consdiffmgr_add_consensus consdiffmgr_add_consensus_nulterm
+
+static int
+mock_ignore_signature_token(const char *digest,
+ ssize_t digest_len,
+ struct directory_token_t *tok,
+ crypto_pk_t *pkey,
+ int flags,
+ const char *doctype)
+{
+ (void)digest;
+ (void)digest_len;
+ (void)tok;
+ (void)pkey;
+ (void)flags;
+ (void)doctype;
+ return 0;
+}
+
static dir_connection_t *
new_dir_conn(void)
{
@@ -116,7 +135,7 @@ test_dir_handle_get_v1_command_not_found(void *data)
conn = new_dir_conn();
// no frontpage configured
- tt_ptr_op(get_dirportfrontpage(), OP_EQ, NULL);
+ tt_ptr_op(relay_get_dirportfrontpage(), OP_EQ, NULL);
/* V1 path */
tt_int_op(directory_handle_command_get(conn, GET("/tor/"), NULL, 0),
@@ -150,9 +169,9 @@ test_dir_handle_get_v1_command(void *data)
(void) data;
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
- MOCK(get_dirportfrontpage, mock_get_dirportfrontpage);
+ MOCK(relay_get_dirportfrontpage, mock_get_dirportfrontpage);
- exp_body = get_dirportfrontpage();
+ exp_body = relay_get_dirportfrontpage();
body_len = strlen(exp_body);
conn = new_dir_conn();
@@ -175,7 +194,7 @@ test_dir_handle_get_v1_command(void *data)
done:
UNMOCK(connection_write_to_buf_impl_);
- UNMOCK(get_dirportfrontpage);
+ UNMOCK(relay_get_dirportfrontpage);
connection_free_minimal(TO_CONN(conn));
tor_free(header);
tor_free(body);
@@ -255,7 +274,7 @@ test_dir_handle_get_rendezvous2_not_found_if_not_encrypted(void *data)
conn = new_dir_conn();
// connection is not encrypted
- tt_assert(!connection_dir_is_encrypted(conn))
+ tt_assert(!connection_dir_is_encrypted(conn));
tt_int_op(directory_handle_command_get(conn, RENDEZVOUS2_GET(), NULL, 0),
OP_EQ, 0);
@@ -312,10 +331,10 @@ test_dir_handle_get_rendezvous2_on_encrypted_conn_not_well_formed(void *data)
TO_CONN(conn)->linked = 1;
tt_assert(connection_dir_is_encrypted(conn));
- //TODO: this cant be reached because rend_valid_descriptor_id() prevents this
- //case to happen. This test is the same as
- //test_dir_handle_get_rendezvous2_on_encrypted_conn_with_invalid_desc_id
- //We should refactor to remove the case from the switch.
+ //TODO: this can't be reached because rend_valid_descriptor_id() prevents
+ //this case to happen. This test is the same as
+ //test_dir_handle_get_rendezvous2_on_encrypted_conn_with_invalid_desc_id We
+ //should refactor to remove the case from the switch.
const char *req = RENDEZVOUS2_GET("1bababababababababababababababab");
tt_int_op(directory_handle_command_get(conn, req, NULL, 0), OP_EQ, 0);
@@ -361,12 +380,13 @@ test_dir_handle_get_rendezvous2_not_found(void *data)
rend_cache_free_all();
}
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+static const routerinfo_t * dhg_tests_router_get_my_routerinfo(void);
+ATTR_UNUSED static int dhg_tests_router_get_my_routerinfo_called = 0;
static routerinfo_t *mock_routerinfo;
static const routerinfo_t *
-NS(router_get_my_routerinfo)(void)
+dhg_tests_router_get_my_routerinfo(void)
{
if (!mock_routerinfo) {
mock_routerinfo = tor_malloc_zero(sizeof(routerinfo_t));
@@ -408,8 +428,7 @@ static or_options_t *mock_options = NULL;
static void
init_mock_options(void)
{
- mock_options = tor_malloc(sizeof(or_options_t));
- memset(mock_options, 0, sizeof(or_options_t));
+ mock_options = options_new();
mock_options->TestingTorNetwork = 1;
mock_options->DataDirectory = tor_strdup(get_fname_rnd("datadir_tmp"));
mock_options->CacheDirectory = tor_strdup(mock_options->DataDirectory);
@@ -429,7 +448,8 @@ static const char microdesc[] =
"MIGJAoGBAMjlHH/daN43cSVRaHBwgUfnszzAhg98EvivJ9Qxfv51mvQUxPjQ07es\n"
"gV/3n8fyh3Kqr/ehi9jxkdgSRfSnmF7giaHL1SLZ29kA7KtST+pBvmTpDtHa3ykX\n"
"Xorc7hJvIyTZoc1HU+5XSynj3gsBE5IGK1ZRzrNS688LnuZMVp1tAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n";
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key QlrOXAa8j3LD31LESsPm/lIKFBwevk2oXdqJcd9SEUc=\n";
static void
test_dir_handle_get_micro_d(void *data)
@@ -698,7 +718,8 @@ test_dir_handle_get_server_descriptors_all(void* data)
helper_setup_fake_routerlist();
//TODO: change to router_get_my_extrainfo when testing "extra" path
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ dhg_tests_router_get_my_routerinfo);
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
// We are one of the routers
@@ -740,7 +761,7 @@ test_dir_handle_get_server_descriptors_all(void* data)
tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
UNMOCK(connection_write_to_buf_impl_);
connection_free_minimal(TO_CONN(conn));
tor_free(header);
@@ -797,7 +818,8 @@ test_dir_handle_get_server_descriptors_authority(void* data)
crypto_pk_t *identity_pkey = pk_generate(0);
(void) data;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ dhg_tests_router_get_my_routerinfo);
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
/* init mock */
@@ -842,7 +864,7 @@ test_dir_handle_get_server_descriptors_authority(void* data)
tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
UNMOCK(connection_write_to_buf_impl_);
tor_free(mock_routerinfo->cache_info.signed_descriptor_body);
tor_free(mock_routerinfo);
@@ -862,7 +884,8 @@ test_dir_handle_get_server_descriptors_fp(void* data)
crypto_pk_t *identity_pkey = pk_generate(0);
(void) data;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ dhg_tests_router_get_my_routerinfo);
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
/* init mock */
@@ -914,7 +937,7 @@ test_dir_handle_get_server_descriptors_fp(void* data)
tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
UNMOCK(connection_write_to_buf_impl_);
tor_free(mock_routerinfo->cache_info.signed_descriptor_body);
tor_free(mock_routerinfo);
@@ -1206,7 +1229,9 @@ test_dir_handle_get_server_keys_authority(void* data)
size_t body_used = 0;
(void) data;
- mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL);
+ mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE,
+ strlen(TEST_CERTIFICATE),
+ NULL);
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
@@ -1356,7 +1381,9 @@ test_dir_handle_get_server_keys_sk(void* data)
size_t body_used = 0;
(void) data;
- mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL);
+ mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE,
+ strlen(TEST_CERTIFICATE),
+ NULL);
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
@@ -1714,13 +1741,14 @@ test_dir_handle_get_status_vote_current_consensus_too_old(void *data)
or_options_free(mock_options); mock_options = NULL;
}
-NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+static int dhg_tests_geoip_get_country_by_addr(const tor_addr_t *addr);
+ATTR_UNUSED static int dhg_tests_geoip_get_country_by_addr_called = 0;
int
-NS(geoip_get_country_by_addr)(const tor_addr_t *addr)
+dhg_tests_geoip_get_country_by_addr(const tor_addr_t *addr)
{
(void)addr;
- CALLED(geoip_get_country_by_addr)++;
+ dhg_tests_geoip_get_country_by_addr_called++;
return 1;
}
@@ -1784,7 +1812,8 @@ test_dir_handle_get_status_vote_current_consensus_ns(void* data)
dirserv_free_all();
clear_geoip_db();
- NS_MOCK(geoip_get_country_by_addr);
+ MOCK(geoip_get_country_by_addr,
+ dhg_tests_geoip_get_country_by_addr);
MOCK(get_options, mock_get_options);
init_mock_options();
@@ -1821,7 +1850,7 @@ test_dir_handle_get_status_vote_current_consensus_ns(void* data)
tt_str_op("ab=8", OP_EQ, hist);
done:
- NS_UNMOCK(geoip_get_country_by_addr);
+ UNMOCK(geoip_get_country_by_addr);
UNMOCK(get_options);
tor_free(header);
tor_free(comp_body);
@@ -1896,7 +1925,8 @@ test_dir_handle_get_status_vote_current_not_found(void* data)
tor_free(header);
}
-#define VOTE_DIGEST "312A4890D4D832597ABBD3089C782DBBFB81E48D"
+/* What vote do we ask for, to get the vote in vote_descriptors.inc ? */
+#define VOTE_DIGEST "78400095d8e834d87135cfc46235c909f0e99911"
static void
status_vote_current_d_test(char **header, char **body, size_t *body_l)
@@ -1978,6 +2008,7 @@ test_dir_handle_get_status_vote_d(void* data)
const char digest[DIGEST_LEN] = "";
(void) data;
+ MOCK(check_signature_token, mock_ignore_signature_token);
clear_dir_servers();
dirvote_free_all();
@@ -2000,12 +2031,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, "foo",
+ &msg_out, &status_out);
tt_assert(pv);
status_vote_current_d_test(&header, &body, &body_used);
@@ -2014,7 +2045,7 @@ test_dir_handle_get_status_vote_d(void* data)
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_assert(strstr(header, "Content-Length: 4403\r\n"));
tt_str_op(VOTE_BODY_V3, OP_EQ, body);
@@ -2027,11 +2058,12 @@ test_dir_handle_get_status_vote_d(void* data)
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_assert(strstr(header, "Content-Length: 4403\r\n"));
tt_str_op(VOTE_BODY_V3, OP_EQ, body);
done:
+ UNMOCK(check_signature_token);
tor_free(header);
tor_free(body);
or_options_free(mock_options); mock_options = NULL;
@@ -2108,6 +2140,7 @@ test_dir_handle_get_status_vote_current_authority_not_found(void* data)
(void) data;
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+ MOCK(check_signature_token, mock_ignore_signature_token);
conn = new_dir_conn();
tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
@@ -2119,6 +2152,7 @@ test_dir_handle_get_status_vote_current_authority_not_found(void* data)
tt_str_op(NOT_FOUND, OP_EQ, header);
done:
+ UNMOCK(check_signature_token);
UNMOCK(connection_write_to_buf_impl_);
connection_free_minimal(TO_CONN(conn));
tor_free(header);
@@ -2132,6 +2166,7 @@ test_dir_handle_get_status_vote_next_authority_not_found(void* data)
(void) data;
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+ MOCK(check_signature_token, mock_ignore_signature_token);
conn = new_dir_conn();
tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
@@ -2143,16 +2178,43 @@ test_dir_handle_get_status_vote_next_authority_not_found(void* data)
tt_str_op(NOT_FOUND, OP_EQ, header);
done:
+ UNMOCK(check_signature_token);
UNMOCK(connection_write_to_buf_impl_);
connection_free_minimal(TO_CONN(conn));
tor_free(header);
}
-NS_DECL(const char*,
-dirvote_get_pending_consensus, (consensus_flavor_t flav));
+static void
+test_dir_handle_get_status_vote_next_bandwidth_not_found(void* data)
+{
+ dir_connection_t *conn = NULL;
+ char *header = NULL;
+ (void) data;
+
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+ MOCK(check_signature_token, mock_ignore_signature_token);
+ conn = new_dir_conn();
+
+ tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
+ GET("/tor/status-vote/next/bandwdith"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ NULL, NULL, 1, 0);
+ tt_assert(header);
+ tt_str_op(NOT_FOUND, OP_EQ, header);
+
+ done:
+ UNMOCK(check_signature_token);
+ UNMOCK(connection_write_to_buf_impl_);
+ connection_free_minimal(TO_CONN(conn));
+ tor_free(header);
+}
+
+static const char* dhg_tests_dirvote_get_pending_consensus(
+ consensus_flavor_t flav);
const char*
-NS(dirvote_get_pending_consensus)(consensus_flavor_t flav)
+dhg_tests_dirvote_get_pending_consensus(consensus_flavor_t flav)
{
(void)flav;
return "pending consensus";
@@ -2165,7 +2227,8 @@ test_dir_handle_get_status_vote_next_consensus(void* data)
size_t body_used = 0;
(void) data;
- NS_MOCK(dirvote_get_pending_consensus);
+ MOCK(dirvote_get_pending_consensus,
+ dhg_tests_dirvote_get_pending_consensus);
status_vote_next_consensus_test(&header, &body, &body_used);
tt_assert(header);
@@ -2178,7 +2241,7 @@ test_dir_handle_get_status_vote_next_consensus(void* data)
tt_str_op("pending consensus", OP_EQ, body);
done:
- NS_UNMOCK(dirvote_get_pending_consensus);
+ UNMOCK(dirvote_get_pending_consensus);
tor_free(header);
tor_free(body);
}
@@ -2191,7 +2254,8 @@ test_dir_handle_get_status_vote_next_consensus_busy(void* data)
(void) data;
MOCK(get_options, mock_get_options);
- NS_MOCK(dirvote_get_pending_consensus);
+ MOCK(dirvote_get_pending_consensus,
+ dhg_tests_dirvote_get_pending_consensus);
//Make it busy
init_mock_options();
@@ -2203,7 +2267,7 @@ test_dir_handle_get_status_vote_next_consensus_busy(void* data)
tt_str_op(SERVER_BUSY, OP_EQ, header);
done:
- NS_UNMOCK(dirvote_get_pending_consensus);
+ UNMOCK(dirvote_get_pending_consensus);
UNMOCK(get_options);
tor_free(header);
tor_free(body);
@@ -2247,11 +2311,10 @@ test_dir_handle_get_status_vote_next_consensus_signatures_not_found(void* data)
tor_free(body);
}
-NS_DECL(const char*,
-dirvote_get_pending_detached_signatures, (void));
+static const char* dhg_tests_dirvote_get_pending_detached_signatures(void);
const char*
-NS(dirvote_get_pending_detached_signatures)(void)
+dhg_tests_dirvote_get_pending_detached_signatures(void)
{
return "pending detached sigs";
}
@@ -2263,7 +2326,8 @@ test_dir_handle_get_status_vote_next_consensus_signatures(void* data)
size_t body_used = 0;
(void) data;
- NS_MOCK(dirvote_get_pending_detached_signatures);
+ MOCK(dirvote_get_pending_detached_signatures,
+ dhg_tests_dirvote_get_pending_detached_signatures);
status_vote_next_consensus_signatures_test(&header, &body, &body_used);
tt_assert(header);
@@ -2276,7 +2340,7 @@ test_dir_handle_get_status_vote_next_consensus_signatures(void* data)
tt_str_op("pending detached sigs", OP_EQ, body);
done:
- NS_UNMOCK(dirvote_get_pending_detached_signatures);
+ UNMOCK(dirvote_get_pending_detached_signatures);
tor_free(header);
tor_free(body);
}
@@ -2288,7 +2352,8 @@ test_dir_handle_get_status_vote_next_consensus_signatures_busy(void* data)
size_t body_used;
(void) data;
- NS_MOCK(dirvote_get_pending_detached_signatures);
+ MOCK(dirvote_get_pending_detached_signatures,
+ dhg_tests_dirvote_get_pending_detached_signatures);
MOCK(get_options, mock_get_options);
//Make it busy
@@ -2302,7 +2367,7 @@ test_dir_handle_get_status_vote_next_consensus_signatures_busy(void* data)
done:
UNMOCK(get_options);
- NS_UNMOCK(dirvote_get_pending_detached_signatures);
+ UNMOCK(dirvote_get_pending_detached_signatures);
tor_free(header);
tor_free(body);
or_options_free(mock_options); mock_options = NULL;
@@ -2320,11 +2385,14 @@ test_dir_handle_get_status_vote_next_authority(void* data)
const char digest[DIGEST_LEN] = "";
(void) data;
+ MOCK(check_signature_token, mock_ignore_signature_token);
clear_dir_servers();
routerlist_free_all();
dirvote_free_all();
- mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL);
+ 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,
@@ -2347,10 +2415,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, "foo",
+ &msg_out, &status_out);
tt_assert(vote);
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
@@ -2367,11 +2435,12 @@ test_dir_handle_get_status_vote_next_authority(void* data)
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_assert(strstr(header, "Content-Length: 4403\r\n"));
tt_str_op(VOTE_BODY_V3, OP_EQ, body);
done:
+ UNMOCK(check_signature_token);
UNMOCK(connection_write_to_buf_impl_);
UNMOCK(get_my_v3_authority_cert);
connection_free_minimal(TO_CONN(conn));
@@ -2386,6 +2455,85 @@ test_dir_handle_get_status_vote_next_authority(void* data)
}
static void
+test_dir_handle_get_status_vote_next_bandwidth(void* data)
+{
+ dir_connection_t *conn = NULL;
+ char *header = NULL, *body = NULL;
+ size_t body_used = 0;
+ (void) data;
+
+ const char *content =
+ "1541171221\n"
+ "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 "
+ "master_key_ed25519=YaqV4vbvPYKucElk297eVdNArDz9HtIwUoIeo0+cVIpQ "
+ "bw=760 nick=Test time=2018-05-08T16:13:26\n";
+
+ init_mock_options();
+ MOCK(get_options, mock_get_options);
+ mock_options->V3BandwidthsFile = tor_strdup(
+ get_fname_rnd("V3BandwidthsFile")
+ );
+
+ write_str_to_file(mock_options->V3BandwidthsFile, content, 0);
+
+ 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/next/bandwidth"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ &body, &body_used, strlen(content)+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: 167\r\n"));
+
+ /* Check cache lifetime */
+ char expbuf[RFC1123_TIME_LEN+1];
+ time_t now = approx_time();
+ /* BANDWIDTH_CACHE_LIFETIME is defined in dircache.c. */
+ format_rfc1123_time(expbuf, (time_t)(now + 30*60));
+ char *expires = NULL;
+ /* Change to 'Cache-control: max-age=%d' if using http/1.1. */
+ tor_asprintf(&expires, "Expires: %s\r\n", expbuf);
+ tt_assert(strstr(header, expires));
+
+ tt_int_op(body_used, OP_EQ, strlen(body));
+ tt_str_op(content, OP_EQ, body);
+
+ tor_free(header);
+ tor_free(body);
+
+ /* Request the file using compression, the result should be the same. */
+ tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
+ GET("/tor/status-vote/next/bandwidth.z"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ &body, &body_used, strlen(content)+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-Encoding: deflate\r\n"));
+
+ /* Since using connection_write_to_buf_mock instead of mocking
+ * connection_buf_add_compress, the content is not actually compressed.
+ * If it would, the size and content would be different than the original.
+ */
+
+ done:
+ UNMOCK(get_options);
+ UNMOCK(connection_write_to_buf_impl_);
+ connection_free_minimal(TO_CONN(conn));
+ tor_free(header);
+ tor_free(body);
+ tor_free(expires);
+ or_options_free(mock_options);
+}
+
+static void
test_dir_handle_get_status_vote_current_authority(void* data)
{
dir_connection_t *conn = NULL;
@@ -2398,11 +2546,14 @@ test_dir_handle_get_status_vote_current_authority(void* data)
dir_server_t *ds = NULL;
(void) data;
+ MOCK(check_signature_token, mock_ignore_signature_token);
clear_dir_servers();
routerlist_free_all();
dirvote_free_all();
- mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL);
+ 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,
@@ -2426,10 +2577,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, "foo",
+ &msg_out, &status_out);
tt_assert(vote);
// move the pending vote to previous vote
@@ -2449,11 +2600,191 @@ test_dir_handle_get_status_vote_current_authority(void* data)
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_assert(strstr(header, "Content-Length: 4403\r\n"));
+
+ tt_str_op(VOTE_BODY_V3, OP_EQ, body);
+
+ done:
+ UNMOCK(check_signature_token);
+ 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();
+}
+
+/* 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;
+
+ MOCK(check_signature_token, mock_ignore_signature_token);
+ 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, "foo",
+ &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, "foo",
+ &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, "foo",
+ &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, "foo",
+ &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, "foo",
+ &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, "foo",
+ &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: 4403\r\n"));
tt_str_op(VOTE_BODY_V3, OP_EQ, body);
done:
+ UNMOCK(check_signature_token);
UNMOCK(connection_write_to_buf_impl_);
UNMOCK(get_my_v3_authority_cert);
connection_free_minimal(TO_CONN(conn));
@@ -2517,6 +2848,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),
@@ -2555,8 +2896,14 @@ 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),
+ DIR_HANDLE_CMD(status_vote_next_bandwidth, 0),
DIR_HANDLE_CMD(status_vote_current_consensus_ns_not_enough_sigs, TT_FORK),
DIR_HANDLE_CMD(status_vote_current_consensus_ns_not_found, TT_FORK),
DIR_HANDLE_CMD(status_vote_current_consensus_too_old, TT_FORK),
diff --git a/src/test/test_dirvote.c b/src/test/test_dirvote.c
new file mode 100644
index 0000000000..b5e57ad071
--- /dev/null
+++ b/src/test/test_dirvote.c
@@ -0,0 +1,671 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_dirvote.c
+ * \brief Unit tests for dirvote related functions
+ */
+#define DIRVOTE_PRIVATE
+
+#include "core/or/or.h"
+#include "feature/dirauth/dirvote.h"
+#include "feature/nodelist/dirlist.h"
+#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/nodelist.h"
+#include "feature/nodelist/routerinfo_st.h"
+#include "feature/nodelist/signed_descriptor_st.h"
+
+#include "test/test.h"
+
+/**
+ * This struct holds the various information that are needed for router
+ * comparison. Each router in the test function has one, and they are all
+ * put in a global digestmap, router_properties
+ */
+typedef struct router_values_t {
+ int is_running;
+ int is_auth;
+ int bw_kb;
+ char digest[DIGEST_LEN];
+} router_values_t;
+/**
+ * This typedef makes declaring digests easier and less verbose
+ */
+typedef char sha1_digest_t[DIGEST_LEN];
+
+// Use of global variable is justified because the functions that have to be
+// mocked take as arguments objects we have no control over
+static digestmap_t *router_properties = NULL;
+// Use of global variable is justified by its use in nodelist.c
+// and is necessary to avoid memory leaks when mocking the
+// function node_get_by_id
+static node_t *running_node;
+static node_t *non_running_node;
+
+/* Allocate memory to the global variables that represent a running
+ * and non-running node
+ */
+#define ALLOCATE_MOCK_NODES() \
+ running_node = tor_malloc(sizeof(node_t)); \
+ running_node->is_running = 1; \
+ non_running_node = tor_malloc(sizeof(node_t)); \
+ non_running_node->is_running = 0;
+
+/* Free the memory allocated to the mock nodes */
+#define FREE_MOCK_NODES() \
+ tor_free(running_node); \
+ tor_free(non_running_node);
+
+static int
+mock_router_digest_is_trusted(const char *digest, dirinfo_type_t type)
+{
+ (void)type;
+ router_values_t *mock_status;
+ mock_status = digestmap_get(router_properties, digest);
+ if (!mock_status) {
+ return -1;
+ }
+ return mock_status->is_auth;
+}
+
+static const node_t *
+mock_node_get_by_id(const char *identity_digest)
+{
+ router_values_t *status;
+ status = digestmap_get(router_properties, identity_digest);
+ if (!status) {
+ return NULL;
+ }
+ if (status->is_running)
+ return running_node;
+ else
+ return non_running_node;
+}
+
+static uint32_t
+mock_dirserv_get_bw(const routerinfo_t *ri)
+{
+ const char *digest = ri->cache_info.identity_digest;
+ router_values_t *status;
+ status = digestmap_get(router_properties, digest);
+ if (!status) {
+ return -1;
+ }
+ return status->bw_kb;
+}
+
+/** Generate a pointer to a router_values_t struct with the arguments as
+ * field values, and return it
+ * The returned pointer has to be freed by the caller.
+ */
+static router_values_t *
+router_values_new(int running, int auth, int bw, char *digest)
+{
+ router_values_t *status = tor_malloc(sizeof(router_values_t));
+ memcpy(status->digest, digest, sizeof(status->digest));
+ status->is_running = running;
+ status->bw_kb = bw;
+ status->is_auth = auth;
+ return status;
+}
+
+/** Given a router_values_t struct, generate a pointer to a routerinfo struct.
+ * In the cache_info member, put the identity digest, and depending on
+ * the family argument, fill the IPv4 or IPv6 address. Return the pointer.
+ * The returned pointer has to be freed by the caller.
+ */
+static routerinfo_t *
+routerinfo_new(router_values_t *status, int family, int addr)
+{
+ routerinfo_t *ri = tor_malloc(sizeof(routerinfo_t));
+ signed_descriptor_t cache_info;
+ memcpy(cache_info.identity_digest, status->digest,
+ sizeof(cache_info.identity_digest));
+ ri->cache_info = cache_info;
+ tor_addr_t ipv6, ipv4;
+ ipv6.family = family;
+ ipv4.family = family;
+ // Set the address of the other IP version to 0
+ if (family == AF_INET) {
+ ipv4.addr.in_addr.s_addr = addr;
+ for (size_t i = 0; i < 16; i++) {
+ ipv6.addr.in6_addr.s6_addr[i] = 0;
+ }
+ } else {
+ for (size_t i = 0; i < 16; i++) {
+ ipv6.addr.in6_addr.s6_addr[i] = addr;
+ }
+ ipv4.addr.in_addr.s_addr = 0;
+ }
+ ri->ipv6_addr = ipv6;
+ ri->ipv4_addr = ipv4;
+ return ri;
+}
+
+static void
+test_dirvote_compare_routerinfo_usefulness(void *arg)
+{
+ (void)arg;
+ MOCK(router_digest_is_trusted_dir_type, mock_router_digest_is_trusted);
+ MOCK(node_get_by_id, mock_node_get_by_id);
+ MOCK(dirserv_get_bandwidth_for_router_kb, mock_dirserv_get_bw);
+ ALLOCATE_MOCK_NODES();
+ router_properties = digestmap_new();
+
+ // The router one is the "least useful" router, every router is compared to
+ // it
+ sha1_digest_t digest_one = "aaaa";
+ router_values_t *status_one = router_values_new(0, 0, 0, digest_one);
+ digestmap_set(router_properties, status_one->digest, status_one);
+ sha1_digest_t digest_two = "bbbb";
+ router_values_t *status_two = router_values_new(0, 1, 0, digest_two);
+ digestmap_set(router_properties, status_two->digest, status_two);
+ sha1_digest_t digest_three = "cccc";
+ router_values_t *status_three = router_values_new(1, 0, 0, digest_three);
+ digestmap_set(router_properties, status_three->digest, status_three);
+ sha1_digest_t digest_four = "dddd";
+ router_values_t *status_four = router_values_new(0, 0, 128, digest_four);
+ digestmap_set(router_properties, status_four->digest, status_four);
+ sha1_digest_t digest_five = "9999";
+ router_values_t *status_five = router_values_new(0, 0, 0, digest_five);
+ digestmap_set(router_properties, status_five->digest, status_five);
+
+ // A router that has auth status is more useful than a non-auth one
+ routerinfo_t *first = routerinfo_new(status_one, AF_INET, 0xf);
+ routerinfo_t *second = routerinfo_new(status_two, AF_INET, 0xf);
+ int a = compare_routerinfo_usefulness(first, second);
+ tt_assert(a == 1);
+ tor_free(second);
+
+ // A running router is more useful than a non running one
+ routerinfo_t *third = routerinfo_new(status_three, AF_INET, 0xf);
+ a = compare_routerinfo_usefulness(first, third);
+ tt_assert(a == 1);
+ tor_free(third);
+
+ // A higher bandwidth is more useful
+ routerinfo_t *fourth = routerinfo_new(status_four, AF_INET, 0xf);
+ a = compare_routerinfo_usefulness(first, fourth);
+ tt_assert(a == 1);
+ tor_free(fourth);
+
+ // In case of tie, the digests are compared
+ routerinfo_t *fifth = routerinfo_new(status_five, AF_INET, 0xf);
+ a = compare_routerinfo_usefulness(first, fifth);
+ tt_assert(a > 0);
+ tor_free(fifth);
+
+done:
+ UNMOCK(router_digest_is_trusted_dir_type);
+ UNMOCK(node_get_by_id);
+ UNMOCK(dirserv_get_bandwidth_for_router_kb);
+ FREE_MOCK_NODES();
+ digestmap_free(router_properties, NULL);
+ tor_free(status_one);
+ tor_free(status_two);
+ tor_free(status_three);
+ tor_free(status_four);
+ tor_free(status_five);
+ tor_free(first);
+}
+
+static void
+test_dirvote_compare_routerinfo_by_ipv4(void *arg)
+{
+ (void)arg;
+ MOCK(router_digest_is_trusted_dir_type, mock_router_digest_is_trusted);
+ MOCK(node_get_by_id, mock_node_get_by_id);
+ MOCK(dirserv_get_bandwidth_for_router_kb, mock_dirserv_get_bw);
+
+ ALLOCATE_MOCK_NODES();
+ router_properties = digestmap_new();
+ sha1_digest_t digest_one = "aaaa";
+ router_values_t *status_one = router_values_new(0, 0, 0, digest_one);
+ digestmap_set(router_properties, status_one->digest, status_one);
+ sha1_digest_t digest_two = "bbbb";
+ router_values_t *status_two = router_values_new(0, 1, 0, digest_two);
+ digestmap_set(router_properties, status_two->digest, status_two);
+
+ // Both routers have an IPv4 address
+ routerinfo_t *first = routerinfo_new(status_one, AF_INET, 1);
+ routerinfo_t *second = routerinfo_new(status_two, AF_INET, 0xf);
+
+ // The first argument's address precedes the seconds' one
+ int a = compare_routerinfo_by_ipv4((const void **)&first,
+ (const void **)&second);
+ tt_assert(a < 0);
+ // The second argument's address precedes the first' one
+ a = compare_routerinfo_by_ipv4((const void **)&second,
+ (const void **)&first);
+ tt_assert(a > 0);
+ tor_addr_copy(&(second->ipv4_addr), &(first->ipv6_addr));
+ // The addresses are equal, they are compared by usefulness,
+ // and first is less useful than second
+ a = compare_routerinfo_by_ipv4((const void **)&first,
+ (const void **)&second);
+ tt_assert(a == 1);
+done:
+ UNMOCK(router_digest_is_trusted_dir_type);
+ UNMOCK(node_get_by_id);
+ UNMOCK(dirserv_get_bandwidth_for_router_kb);
+ FREE_MOCK_NODES();
+ digestmap_free(router_properties, NULL);
+ tor_free(status_one);
+ tor_free(status_two);
+ tor_free(first);
+ tor_free(second);
+}
+
+static void
+test_dirvote_compare_routerinfo_by_ipv6(void *arg)
+{
+ (void)arg;
+ MOCK(router_digest_is_trusted_dir_type, mock_router_digest_is_trusted);
+ MOCK(node_get_by_id, mock_node_get_by_id);
+ MOCK(dirserv_get_bandwidth_for_router_kb, mock_dirserv_get_bw);
+
+ ALLOCATE_MOCK_NODES();
+ router_properties = digestmap_new();
+ char digest_one[DIGEST_LEN] = "aaaa";
+ router_values_t *status_one = router_values_new(0, 0, 0, digest_one);
+ digestmap_set(router_properties, status_one->digest, status_one);
+ char digest_two[DIGEST_LEN] = "bbbb";
+ router_values_t *status_two = router_values_new(0, 1, 0, digest_two);
+ digestmap_set(router_properties, status_two->digest, status_two);
+
+ // Both routers have an IPv6 address
+ routerinfo_t *first = routerinfo_new(status_one, AF_INET6, 1);
+ routerinfo_t *second = routerinfo_new(status_two, AF_INET6, 0xf);
+
+ // The first argument's address precedes the seconds' one
+ int a = compare_routerinfo_by_ipv6((const void **)&first,
+ (const void **)&second);
+ tt_assert(a < 0);
+ // The second argument's address precedes the first' one
+ a = compare_routerinfo_by_ipv6((const void **)&second,
+ (const void **)&first);
+ tt_assert(a > 0);
+ tor_addr_copy(&(first->ipv6_addr), &(second->ipv6_addr));
+ // The addresses are equal, they are compared by usefulness,
+ // and first is less useful than second
+ a = compare_routerinfo_by_ipv6((const void **)&first,
+ (const void **)&second);
+ tt_assert(a == 1);
+done:
+ UNMOCK(router_digest_is_trusted_dir_type);
+ UNMOCK(node_get_by_id);
+ UNMOCK(dirserv_get_bandwidth_for_router_kb);
+ FREE_MOCK_NODES();
+ digestmap_free(router_properties, NULL);
+ tor_free(status_one);
+ tor_free(status_two);
+ tor_free(first);
+ tor_free(second);
+}
+
+/** Create routers values and routerinfos that always have the same
+ * characteristics, and add them to the global digestmap. This macro is here to
+ * avoid duplicated code fragments.
+ * The created name##_val pointer should be freed by the caller (and cannot
+ * be freed in the macro as it causes a heap-after-free error)
+ */
+#define CREATE_ROUTER(digest, name, addr, ip_version) \
+ sha1_digest_t name##_digest = digest; \
+ name##_val = router_values_new(1, 1, 1, name##_digest); \
+ digestmap_set(router_properties, name##_digest, name##_val); \
+ name##_ri = routerinfo_new(name##_val, ip_version, addr);
+
+#define ROUTER_FREE(name) \
+ tor_free(name##_val); \
+ tor_free(name##_ri);
+
+/** Test to see if the returned routers are exactly the ones that should be
+ * flagged as sybils : we test for inclusion then for number of elements
+ */
+#define TEST_SYBIL(true_sybil, possible_sybil) \
+ DIGESTMAP_FOREACH (true_sybil, sybil_id, void *, ignore) { \
+ (void)ignore; \
+ tt_assert(digestmap_get(possible_sybil, sybil_id)); \
+ } \
+ DIGESTMAP_FOREACH_END; \
+ tt_assert(digestmap_size(true_sybil) == digestmap_size(possible_sybil));
+
+static void
+test_dirvote_get_sybil_by_ip_version_ipv4(void *arg)
+{
+ // It is assumed that global_dirauth_options.AuthDirMaxServersPerAddr == 2
+ (void)arg;
+ router_values_t *aaaa_val=NULL, *bbbb_val=NULL, *cccc_val=NULL,
+ *dddd_val=NULL, *eeee_val=NULL, *ffff_val=NULL, *gggg_val=NULL,
+ *hhhh_val=NULL;
+ routerinfo_t *aaaa_ri=NULL, *bbbb_ri=NULL, *cccc_ri=NULL,
+ *dddd_ri=NULL, *eeee_ri=NULL, *ffff_ri=NULL, *gggg_ri=NULL,
+ *hhhh_ri=NULL;
+
+ MOCK(router_digest_is_trusted_dir_type, mock_router_digest_is_trusted);
+ MOCK(node_get_by_id, mock_node_get_by_id);
+ MOCK(dirserv_get_bandwidth_for_router_kb, mock_dirserv_get_bw);
+ ALLOCATE_MOCK_NODES();
+ router_properties = digestmap_new();
+ smartlist_t *routers_ipv4;
+ routers_ipv4 = smartlist_new();
+ digestmap_t *true_sybil_routers = NULL;
+ true_sybil_routers = digestmap_new();
+ digestmap_t *omit_as_sybil;
+
+ CREATE_ROUTER("aaaa", aaaa, 123, AF_INET);
+ smartlist_add(routers_ipv4, aaaa_ri);
+ CREATE_ROUTER("bbbb", bbbb, 123, AF_INET);
+ smartlist_add(routers_ipv4, bbbb_ri);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv4, AF_INET);
+ tt_assert(digestmap_isempty(omit_as_sybil) == 1);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("cccc", cccc, 123, AF_INET);
+ smartlist_add(routers_ipv4, cccc_ri);
+ digestmap_set(true_sybil_routers, cccc_digest, cccc_digest);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv4, AF_INET);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("dddd", dddd, 123, AF_INET);
+ smartlist_add(routers_ipv4, dddd_ri);
+ digestmap_set(true_sybil_routers, dddd_digest, dddd_digest);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv4, AF_INET);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("eeee", eeee, 456, AF_INET);
+ smartlist_add(routers_ipv4, eeee_ri);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv4, AF_INET);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("ffff", ffff, 456, AF_INET);
+ smartlist_add(routers_ipv4, ffff_ri);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv4, AF_INET);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("gggg", gggg, 456, AF_INET);
+ smartlist_add(routers_ipv4, gggg_ri);
+ digestmap_set(true_sybil_routers, gggg_digest, gggg_digest);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv4, AF_INET);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("hhhh", hhhh, 456, AF_INET);
+ smartlist_add(routers_ipv4, hhhh_ri);
+ digestmap_set(true_sybil_routers, hhhh_digest, hhhh_digest);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv4, AF_INET);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+
+done:
+ UNMOCK(router_digest_is_trusted_dir_type);
+ UNMOCK(node_get_by_id);
+ UNMOCK(dirserv_get_bandwidth_for_router_kb);
+ FREE_MOCK_NODES();
+ digestmap_free(router_properties, NULL);
+ smartlist_free(routers_ipv4);
+ digestmap_free(omit_as_sybil, NULL);
+ digestmap_free(true_sybil_routers, NULL);
+ ROUTER_FREE(aaaa);
+ ROUTER_FREE(bbbb);
+ ROUTER_FREE(cccc);
+ ROUTER_FREE(dddd);
+ ROUTER_FREE(eeee);
+ ROUTER_FREE(ffff);
+ ROUTER_FREE(gggg);
+ ROUTER_FREE(hhhh);
+}
+
+static void
+test_dirvote_get_sybil_by_ip_version_ipv6(void *arg)
+{
+ router_values_t *aaaa_val=NULL, *bbbb_val=NULL, *cccc_val=NULL,
+ *dddd_val=NULL, *eeee_val=NULL, *ffff_val=NULL, *gggg_val=NULL,
+ *hhhh_val=NULL;
+ routerinfo_t *aaaa_ri=NULL, *bbbb_ri=NULL, *cccc_ri=NULL,
+ *dddd_ri=NULL, *eeee_ri=NULL, *ffff_ri=NULL, *gggg_ri=NULL,
+ *hhhh_ri=NULL;
+
+ // It is assumed that global_dirauth_options.AuthDirMaxServersPerAddr == 2
+ (void)arg;
+ MOCK(router_digest_is_trusted_dir_type, mock_router_digest_is_trusted);
+ MOCK(node_get_by_id, mock_node_get_by_id);
+ MOCK(dirserv_get_bandwidth_for_router_kb, mock_dirserv_get_bw);
+ ALLOCATE_MOCK_NODES();
+ router_properties = digestmap_new();
+ smartlist_t *routers_ipv6;
+ routers_ipv6 = smartlist_new();
+ digestmap_t *true_sybil_routers = NULL;
+ true_sybil_routers = digestmap_new();
+ digestmap_t *omit_as_sybil;
+
+ CREATE_ROUTER("aaaa", aaaa, 123, AF_INET6);
+ smartlist_add(routers_ipv6, aaaa_ri);
+ CREATE_ROUTER("bbbb", bbbb, 123, AF_INET6);
+ smartlist_add(routers_ipv6, bbbb_ri);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv6, AF_INET6);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("cccc", cccc, 123, AF_INET6);
+ smartlist_add(routers_ipv6, cccc_ri);
+ digestmap_set(true_sybil_routers, cccc_digest, cccc_digest);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv6, AF_INET6);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("dddd", dddd, 123, AF_INET6);
+ smartlist_add(routers_ipv6, dddd_ri);
+ digestmap_set(true_sybil_routers, dddd_digest, dddd_digest);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv6, AF_INET6);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("eeee", eeee, 456, AF_INET6);
+ smartlist_add(routers_ipv6, eeee_ri);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv6, AF_INET6);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("ffff", ffff, 456, AF_INET6);
+ smartlist_add(routers_ipv6, ffff_ri);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv6, AF_INET6);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("gggg", gggg, 456, AF_INET6);
+ smartlist_add(routers_ipv6, gggg_ri);
+ digestmap_set(true_sybil_routers, gggg_digest, gggg_digest);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv6, AF_INET6);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("hhhh", hhhh, 456, AF_INET6);
+ smartlist_add(routers_ipv6, hhhh_ri);
+ digestmap_set(true_sybil_routers, hhhh_digest, hhhh_digest);
+ omit_as_sybil = get_sybil_list_by_ip_version(routers_ipv6, AF_INET6);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+done:
+ UNMOCK(router_digest_is_trusted_dir_type);
+ UNMOCK(node_get_by_id);
+ UNMOCK(dirserv_get_bandwidth_for_router_kb);
+ FREE_MOCK_NODES();
+ digestmap_free(router_properties, NULL);
+ digestmap_free(true_sybil_routers, NULL);
+ smartlist_free(routers_ipv6);
+ digestmap_free(omit_as_sybil, NULL);
+ ROUTER_FREE(aaaa);
+ ROUTER_FREE(bbbb);
+ ROUTER_FREE(cccc);
+ ROUTER_FREE(dddd);
+ ROUTER_FREE(eeee);
+ ROUTER_FREE(ffff);
+ ROUTER_FREE(gggg);
+ ROUTER_FREE(hhhh);
+}
+
+static void
+test_dirvote_get_all_possible_sybil(void *arg)
+{
+ router_values_t *aaaa_val=NULL, *bbbb_val=NULL, *cccc_val=NULL,
+ *dddd_val=NULL, *eeee_val=NULL, *ffff_val=NULL, *gggg_val=NULL,
+ *hhhh_val=NULL, *iiii_val=NULL, *jjjj_val=NULL, *kkkk_val=NULL,
+ *llll_val=NULL, *mmmm_val=NULL, *nnnn_val=NULL, *oooo_val=NULL,
+ *pppp_val=NULL;
+ routerinfo_t *aaaa_ri=NULL, *bbbb_ri=NULL, *cccc_ri=NULL,
+ *dddd_ri=NULL, *eeee_ri=NULL, *ffff_ri=NULL, *gggg_ri=NULL,
+ *hhhh_ri=NULL, *iiii_ri=NULL, *jjjj_ri=NULL, *kkkk_ri=NULL,
+ *llll_ri=NULL, *mmmm_ri=NULL, *nnnn_ri=NULL, *oooo_ri=NULL,
+ *pppp_ri=NULL;
+
+ // It is assumed that global_dirauth_options.AuthDirMaxServersPerAddr == 2
+ (void)arg;
+ MOCK(router_digest_is_trusted_dir_type, mock_router_digest_is_trusted);
+ MOCK(node_get_by_id, mock_node_get_by_id);
+ MOCK(dirserv_get_bandwidth_for_router_kb, mock_dirserv_get_bw);
+ ALLOCATE_MOCK_NODES();
+ router_properties = digestmap_new();
+ smartlist_t *routers;
+ routers = smartlist_new();
+ digestmap_t *true_sybil_routers = NULL;
+ true_sybil_routers = digestmap_new();
+ digestmap_t *omit_as_sybil;
+
+ CREATE_ROUTER("aaaa", aaaa, 123, AF_INET);
+ smartlist_add(routers, aaaa_ri);
+ CREATE_ROUTER("bbbb", bbbb, 123, AF_INET);
+ smartlist_add(routers, bbbb_ri);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("cccc", cccc, 123, AF_INET);
+ smartlist_add(routers, cccc_ri);
+ digestmap_set(true_sybil_routers, cccc_digest, cccc_digest);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("dddd", dddd, 123, AF_INET);
+ smartlist_add(routers, dddd_ri);
+ digestmap_set(true_sybil_routers, dddd_digest, dddd_digest);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("eeee", eeee, 456, AF_INET);
+ smartlist_add(routers, eeee_ri);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("ffff", ffff, 456, AF_INET);
+ smartlist_add(routers, ffff_ri);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("gggg", gggg, 456, AF_INET);
+ smartlist_add(routers, gggg_ri);
+ digestmap_set(true_sybil_routers, gggg_digest, gggg_digest);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("hhhh", hhhh, 456, AF_INET);
+ smartlist_add(routers, hhhh_ri);
+ digestmap_set(true_sybil_routers, hhhh_digest, hhhh_digest);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("iiii", iiii, 123, AF_INET6);
+ smartlist_add(routers, iiii_ri);
+ CREATE_ROUTER("jjjj", jjjj, 123, AF_INET6);
+ smartlist_add(routers, jjjj_ri);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("kkkk", kkkk, 123, AF_INET6);
+ smartlist_add(routers, kkkk_ri);
+ digestmap_set(true_sybil_routers, kkkk_digest, kkkk_digest);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil,NULL);
+
+ CREATE_ROUTER("llll", llll, 123, AF_INET6);
+ smartlist_add(routers, llll_ri);
+ digestmap_set(true_sybil_routers, llll_digest, llll_digest);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil,NULL);
+
+ CREATE_ROUTER("mmmm", mmmm, 456, AF_INET6);
+ smartlist_add(routers, mmmm_ri);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("nnnn", nnnn, 456, AF_INET6);
+ smartlist_add(routers, nnnn_ri);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("oooo", oooo, 456, AF_INET6);
+ smartlist_add(routers, oooo_ri);
+ digestmap_set(true_sybil_routers, oooo_digest, oooo_digest);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+
+ CREATE_ROUTER("pppp", pppp, 456, AF_INET6);
+ smartlist_add(routers, pppp_ri);
+ digestmap_set(true_sybil_routers, pppp_digest, pppp_digest);
+ omit_as_sybil = get_all_possible_sybil(routers);
+ TEST_SYBIL(true_sybil_routers, omit_as_sybil);
+
+done:
+ UNMOCK(router_digest_is_trusted_dir_type);
+ UNMOCK(node_get_by_id);
+ UNMOCK(dirserv_get_bandwidth_for_router_kb);
+ FREE_MOCK_NODES();
+ digestmap_free(router_properties, NULL);
+ smartlist_free(routers);
+ digestmap_free(omit_as_sybil, NULL);
+ digestmap_free(true_sybil_routers, NULL);
+ ROUTER_FREE(aaaa);
+ ROUTER_FREE(bbbb);
+ ROUTER_FREE(cccc);
+ ROUTER_FREE(dddd);
+ ROUTER_FREE(eeee);
+ ROUTER_FREE(ffff);
+ ROUTER_FREE(gggg);
+ ROUTER_FREE(hhhh);
+ ROUTER_FREE(iiii);
+ ROUTER_FREE(jjjj);
+ ROUTER_FREE(kkkk);
+ ROUTER_FREE(llll);
+ ROUTER_FREE(mmmm);
+ ROUTER_FREE(nnnn);
+ ROUTER_FREE(oooo);
+ ROUTER_FREE(pppp);
+}
+
+#define NODE(name, flags) \
+ { \
+ #name, test_dirvote_##name, (flags), NULL, NULL \
+ }
+
+struct testcase_t dirvote_tests[] = {
+ NODE(compare_routerinfo_usefulness, TT_FORK),
+ NODE(compare_routerinfo_by_ipv6, TT_FORK),
+ NODE(compare_routerinfo_by_ipv4, TT_FORK),
+ NODE(get_sybil_by_ip_version_ipv4, TT_FORK),
+ NODE(get_sybil_by_ip_version_ipv6, TT_FORK),
+ NODE(get_all_possible_sybil, TT_FORK),
+ END_OF_TESTCASES};
diff --git a/src/test/test_dispatch.c b/src/test/test_dispatch.c
new file mode 100644
index 0000000000..f7f8ecdc03
--- /dev/null
+++ b/src/test/test_dispatch.c
@@ -0,0 +1,278 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define DISPATCH_NEW_PRIVATE
+#define DISPATCH_PRIVATE
+
+#include "test/test.h"
+
+#include "lib/dispatch/dispatch.h"
+#include "lib/dispatch/dispatch_cfg.h"
+#include "lib/dispatch/dispatch_st.h"
+#include "lib/dispatch/msgtypes.h"
+
+#include "lib/log/escape.h"
+#include "lib/malloc/malloc.h"
+#include "lib/string/printf.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static dispatch_t *dispatcher_in_use=NULL;
+
+static void
+test_dispatch_max_in_u16_sl(void *arg)
+{
+ (void)arg;
+ smartlist_t *sl = smartlist_new();
+ uint16_t nums[] = { 10, 20, 30 };
+ tt_int_op(-1, OP_EQ, max_in_u16_sl(sl, -1));
+
+ smartlist_add(sl, NULL);
+ tt_int_op(-1, OP_EQ, max_in_u16_sl(sl, -1));
+
+ smartlist_add(sl, &nums[1]);
+ tt_int_op(20, OP_EQ, max_in_u16_sl(sl, -1));
+
+ smartlist_add(sl, &nums[0]);
+ tt_int_op(20, OP_EQ, max_in_u16_sl(sl, -1));
+
+ smartlist_add(sl, NULL);
+ tt_int_op(20, OP_EQ, max_in_u16_sl(sl, -1));
+
+ smartlist_add(sl, &nums[2]);
+ tt_int_op(30, OP_EQ, max_in_u16_sl(sl, -1));
+
+ done:
+ smartlist_free(sl);
+}
+
+/* Construct an empty dispatch_t. */
+static void
+test_dispatch_empty(void *arg)
+{
+ (void)arg;
+
+ dispatch_t *d=NULL;
+ dispatch_cfg_t *cfg=NULL;
+
+ cfg = dcfg_new();
+ d = dispatch_new(cfg);
+ tt_assert(d);
+
+ done:
+ dispatch_free(d);
+ dcfg_free(cfg);
+}
+
+static int total_recv1_simple = 0;
+static int total_recv2_simple = 0;
+
+static void
+simple_recv1(const msg_t *m)
+{
+ total_recv1_simple += m->aux_data__.u64;
+}
+
+static char *recv2_received = NULL;
+
+static void
+simple_recv2(const msg_t *m)
+{
+ tor_free(recv2_received);
+ recv2_received = dispatch_fmt_msg_data(dispatcher_in_use, m);
+
+ total_recv2_simple += m->aux_data__.u64*10;
+}
+
+/* Construct a dispatch_t with two messages, make sure that they both get
+ * delivered. */
+static void
+test_dispatch_simple(void *arg)
+{
+ (void)arg;
+
+ dispatch_t *d=NULL;
+ dispatch_cfg_t *cfg=NULL;
+ int r;
+
+ cfg = dcfg_new();
+ r = dcfg_msg_set_type(cfg,0,0);
+ r += dcfg_msg_set_chan(cfg,0,0);
+ r += dcfg_add_recv(cfg,0,1,simple_recv1);
+ r += dcfg_msg_set_type(cfg,1,0);
+ r += dcfg_msg_set_chan(cfg,1,0);
+ r += dcfg_add_recv(cfg,1,1,simple_recv2);
+ r += dcfg_add_recv(cfg,1,1,simple_recv2); /* second copy */
+ tt_int_op(r, OP_EQ, 0);
+
+ d = dispatch_new(cfg);
+ tt_assert(d);
+ dispatcher_in_use = d;
+
+ msg_aux_data_t data = {.u64 = 7};
+ r = dispatch_send(d, 99, 0, 0, 0, data);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(total_recv1_simple, OP_EQ, 0);
+
+ r = dispatch_flush(d, 0, INT_MAX);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(total_recv1_simple, OP_EQ, 7);
+ tt_int_op(total_recv2_simple, OP_EQ, 0);
+
+ total_recv1_simple = 0;
+ r = dispatch_send(d, 99, 0, 1, 0, data);
+ tt_int_op(r, OP_EQ, 0);
+ r = dispatch_flush(d, 0, INT_MAX);
+ tt_int_op(total_recv1_simple, OP_EQ, 0);
+ tt_int_op(total_recv2_simple, OP_EQ, 140);
+
+ tt_str_op(recv2_received, OP_EQ, "<>"); // no format function was set.
+
+ done:
+ dispatch_free(d);
+ dcfg_free(cfg);
+ tor_free(recv2_received);
+}
+
+/* Construct a dispatch_t with a message and no receiver; make sure that it
+ * gets dropped properly. */
+static void
+test_dispatch_no_recipient(void *arg)
+{
+ (void)arg;
+
+ dispatch_t *d=NULL;
+ dispatch_cfg_t *cfg=NULL;
+ int r;
+
+ cfg = dcfg_new();
+ r = dcfg_msg_set_type(cfg,0,0);
+ r += dcfg_msg_set_chan(cfg,0,0);
+ tt_int_op(r, OP_EQ, 0);
+
+ d = dispatch_new(cfg);
+ tt_assert(d);
+ dispatcher_in_use = d;
+
+ msg_aux_data_t data = { .u64 = 7};
+ r = dispatch_send(d, 99, 0, 0, 0, data);
+ tt_int_op(r, OP_EQ, 0);
+
+ r = dispatch_flush(d, 0, INT_MAX);
+ tt_int_op(r, OP_EQ, 0);
+
+ done:
+ dispatch_free(d);
+ dcfg_free(cfg);
+}
+
+struct coord_t { int x; int y; };
+static void
+free_coord(msg_aux_data_t d)
+{
+ tor_free(d.ptr);
+}
+static char *
+fmt_coord(msg_aux_data_t d)
+{
+ char *v;
+ struct coord_t *c = d.ptr;
+ tor_asprintf(&v, "[%d, %d]", c->x, c->y);
+ return v;
+}
+static dispatch_typefns_t coord_fns = {
+ .fmt_fn = fmt_coord,
+ .free_fn = free_coord,
+};
+static void
+alert_run_immediate(dispatch_t *d, channel_id_t ch, void *arg)
+{
+ (void)arg;
+ dispatch_flush(d, ch, INT_MAX);
+}
+
+static char *received_data=NULL;
+
+static void
+recv_typed_data(const msg_t *m)
+{
+ tor_free(received_data);
+ received_data = dispatch_fmt_msg_data(dispatcher_in_use, m);
+}
+
+static void
+test_dispatch_with_types(void *arg)
+{
+ (void)arg;
+
+ dispatch_t *d=NULL;
+ dispatch_cfg_t *cfg=NULL;
+ int r;
+
+ cfg = dcfg_new();
+ r = dcfg_msg_set_type(cfg,5,3);
+ r += dcfg_msg_set_chan(cfg,5,2);
+ r += dcfg_add_recv(cfg,5,0,recv_typed_data);
+ r += dcfg_type_set_fns(cfg,3,&coord_fns);
+ tt_int_op(r, OP_EQ, 0);
+
+ d = dispatch_new(cfg);
+ tt_assert(d);
+ dispatcher_in_use = d;
+
+ /* Make this message get run immediately. */
+ r = dispatch_set_alert_fn(d, 2, alert_run_immediate, NULL);
+ tt_int_op(r, OP_EQ, 0);
+
+ struct coord_t *xy = tor_malloc(sizeof(*xy));
+ xy->x = 13;
+ xy->y = 37;
+ msg_aux_data_t data = {.ptr = xy};
+ r = dispatch_send(d, 99/*sender*/, 2/*channel*/, 5/*msg*/, 3/*type*/, data);
+ tt_int_op(r, OP_EQ, 0);
+ tt_str_op(received_data, OP_EQ, "[13, 37]");
+
+ done:
+ dispatch_free(d);
+ dcfg_free(cfg);
+ tor_free(received_data);
+ dispatcher_in_use = NULL;
+}
+
+static void
+test_dispatch_bad_type_setup(void *arg)
+{
+ (void)arg;
+ static dispatch_typefns_t fns;
+ dispatch_cfg_t *cfg = dcfg_new();
+
+ tt_int_op(0, OP_EQ, dcfg_type_set_fns(cfg, 7, &coord_fns));
+
+ fns = coord_fns;
+ fns.fmt_fn = NULL;
+ tt_int_op(-1, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns));
+
+ fns = coord_fns;
+ fns.free_fn = NULL;
+ tt_int_op(-1, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns));
+
+ fns = coord_fns;
+ tt_int_op(0, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns));
+
+ done:
+ dcfg_free(cfg);
+}
+
+#define T(name) \
+ { #name, test_dispatch_ ## name, TT_FORK, NULL, NULL }
+
+struct testcase_t dispatch_tests[] = {
+ T(max_in_u16_sl),
+ T(empty),
+ T(simple),
+ T(no_recipient),
+ T(with_types),
+ T(bad_type_setup),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_dns.c b/src/test/test_dns.c
index 41a56f65d8..299321ab64 100644
--- a/src/test/test_dns.c
+++ b/src/test/test_dns.c
@@ -1,6 +1,7 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#include "orconfig.h"
#include "core/or/or.h"
#include "test/test.h"
@@ -13,29 +14,81 @@
#include "core/or/edge_connection_st.h"
#include "core/or/or_circuit_st.h"
+#include "app/config/or_options_st.h"
+#include "app/config/config.h"
-#define NS_MODULE dns
+#include <event2/event.h>
+#include <event2/dns.h>
-#define NS_SUBMODULE clip_ttl
+#ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR
+
+static or_options_t options = {
+ .ORPort_set = 1,
+};
+
+static const or_options_t *
+mock_get_options(void)
+{
+ return &options;
+}
static void
-NS(test_main)(void *arg)
+test_dns_configure_ns_fallback(void *arg)
{
(void)arg;
+ tor_addr_t *nameserver_addr = NULL;
- uint32_t ttl_mid = MIN_DNS_TTL_AT_EXIT / 2 + MAX_DNS_TTL_AT_EXIT / 2;
+ MOCK(get_options, mock_get_options);
- 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);
+ options.ServerDNSResolvConfFile = (char *)"no_such_file!!!";
- done:
+ dns_init(); // calls configure_nameservers()
+
+ tt_int_op(number_of_configured_nameservers(), OP_EQ, 1);
+
+ nameserver_addr = configured_nameserver_address(0);
+
+ tt_assert(tor_addr_family(nameserver_addr) == AF_INET);
+ tt_assert(tor_addr_eq_ipv4h(nameserver_addr, 0x7f000001));
+
+#ifndef _WIN32
+ tor_free(nameserver_addr);
+
+ options.ServerDNSResolvConfFile = (char *)"/dev/null";
+
+ dns_init();
+
+ tt_int_op(number_of_configured_nameservers(), OP_EQ, 1);
+
+ nameserver_addr = configured_nameserver_address(0);
+
+ tt_assert(tor_addr_family(nameserver_addr) == AF_INET);
+ tt_assert(tor_addr_eq_ipv4h(nameserver_addr, 0x7f000001));
+#endif /* !defined(_WIN32) */
+
+ UNMOCK(get_options);
+
+ done:
+ tor_free(nameserver_addr);
return;
}
-#undef NS_SUBMODULE
+#endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */
+
+static void
+test_dns_clip_ttl(void *arg)
+{
+ (void)arg;
-#define NS_SUBMODULE resolve
+ uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_TTL / 2;
+
+ 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;
+}
static int resolve_retval = 0;
static int resolve_made_conn_pending = 0;
@@ -44,10 +97,11 @@ static cached_resolve_t *cache_entry_mock = NULL;
static int n_fake_impl = 0;
-NS_DECL(int, dns_resolve_impl, (edge_connection_t *exitconn, int is_resolve,
- or_circuit_t *oncirc, char **hostname_out,
- int *made_connection_pending_out,
- cached_resolve_t **resolve_out));
+static int dns_resolve_dns_resolve_impl(edge_connection_t *exitconn,
+ int is_resolve, or_circuit_t *oncirc,
+ char **hostname_out, int *made_connection_pending_out,
+ cached_resolve_t **resolve_out);
+ATTR_UNUSED static int dns_resolve_dns_resolve_impl_called = 0;
/** This will be our configurable substitute for <b>dns_resolve_impl</b> in
* dns.c. It will return <b>resolve_retval</b>,
@@ -58,7 +112,7 @@ NS_DECL(int, dns_resolve_impl, (edge_connection_t *exitconn, int is_resolve,
* 1.
*/
static int
-NS(dns_resolve_impl)(edge_connection_t *exitconn, int is_resolve,
+dns_resolve_dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
or_circuit_t *oncirc, char **hostname_out,
int *made_connection_pending_out,
cached_resolve_t **resolve_out)
@@ -88,7 +142,7 @@ static uint8_t last_answer_type = 0;
static cached_resolve_t *last_resolved;
static void
-NS(send_resolved_cell)(edge_connection_t *conn, uint8_t answer_type,
+dns_resolve_send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
const cached_resolve_t *resolved)
{
conn_for_resolved_cell = conn;
@@ -104,7 +158,7 @@ static int n_send_resolved_hostname_cell_replacement = 0;
static char *last_resolved_hostname = NULL;
static void
-NS(send_resolved_hostname_cell)(edge_connection_t *conn,
+dns_resolve_send_resolved_hostname_cell(edge_connection_t *conn,
const char *hostname)
{
conn_for_resolved_cell = conn;
@@ -118,7 +172,7 @@ NS(send_resolved_hostname_cell)(edge_connection_t *conn,
static int n_dns_cancel_pending_resolve_replacement = 0;
static void
-NS(dns_cancel_pending_resolve)(const char *address)
+dns_resolve_dns_cancel_pending_resolve(const char *address)
{
(void) address;
n_dns_cancel_pending_resolve_replacement++;
@@ -128,7 +182,7 @@ static int n_connection_free = 0;
static connection_t *last_freed_conn = NULL;
static void
-NS(connection_free_)(connection_t *conn)
+dns_resolve_connection_free_(connection_t *conn)
{
n_connection_free++;
@@ -136,7 +190,7 @@ NS(connection_free_)(connection_t *conn)
}
static void
-NS(test_main)(void *arg)
+test_dns_resolve(void *arg)
{
(void) arg;
int retval;
@@ -155,9 +209,12 @@ NS(test_main)(void *arg)
memset(exitconn,0,sizeof(edge_connection_t));
memset(nextconn,0,sizeof(edge_connection_t));
- NS_MOCK(dns_resolve_impl);
- NS_MOCK(send_resolved_cell);
- NS_MOCK(send_resolved_hostname_cell);
+ MOCK(dns_resolve_impl,
+ dns_resolve_dns_resolve_impl);
+ MOCK(send_resolved_cell,
+ dns_resolve_send_resolved_cell);
+ MOCK(send_resolved_hostname_cell,
+ dns_resolve_send_resolved_hostname_cell);
/*
* CASE 1: dns_resolve_impl returns 1 and sets a hostname. purpose is
@@ -270,8 +327,10 @@ NS(test_main)(void *arg)
* on exitconn with type being RESOLVED_TYPE_ERROR.
*/
- NS_MOCK(dns_cancel_pending_resolve);
- NS_MOCK(connection_free_);
+ MOCK(dns_cancel_pending_resolve,
+ dns_resolve_dns_cancel_pending_resolve);
+ MOCK(connection_free_,
+ dns_resolve_connection_free_);
exitconn->on_circuit = &(on_circuit->base_);
exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
@@ -294,11 +353,11 @@ NS(test_main)(void *arg)
tt_assert(last_freed_conn == TO_CONN(exitconn));
done:
- NS_UNMOCK(dns_resolve_impl);
- NS_UNMOCK(send_resolved_cell);
- NS_UNMOCK(send_resolved_hostname_cell);
- NS_UNMOCK(dns_cancel_pending_resolve);
- NS_UNMOCK(connection_free_);
+ UNMOCK(dns_resolve_impl);
+ UNMOCK(send_resolved_cell);
+ UNMOCK(send_resolved_hostname_cell);
+ UNMOCK(dns_cancel_pending_resolve);
+ UNMOCK(connection_free_);
tor_free(on_circuit);
tor_free(exitconn);
tor_free(nextconn);
@@ -308,8 +367,6 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
-
/** Create an <b>edge_connection_t</b> instance that is considered a
* valid exit connection by asserts in dns_resolve_impl.
*/
@@ -326,8 +383,6 @@ create_valid_exitconn(void)
return exitconn;
}
-#define NS_SUBMODULE ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve)
-
/*
* Given that <b>exitconn->base_.address</b> is IP address string, we
* want dns_resolve_impl() to parse it and store in
@@ -336,7 +391,7 @@ create_valid_exitconn(void)
*/
static void
-NS(test_main)(void *arg)
+test_dns_impl_addr_is_ip(void *arg)
{
int retval;
int made_pending;
@@ -369,21 +424,17 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, non_exit)
-
/** Given that Tor instance is not configured as an exit node, we want
* dns_resolve_impl() to fail with return value -1.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_non_exit_router_my_exit_policy_is_reject_star(void)
{
return 1;
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_non_exit(void *arg)
{
int retval;
int made_pending;
@@ -395,7 +446,8 @@ NS(test_main)(void *arg)
TO_CONN(exitconn)->address = tor_strdup("torproject.org");
- NS_MOCK(router_my_exit_policy_is_reject_star);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_non_exit_router_my_exit_policy_is_reject_star);
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
NULL);
@@ -406,27 +458,23 @@ NS(test_main)(void *arg)
tor_free(TO_CONN(exitconn)->address);
tor_free(exitconn);
tor_free(on_circ);
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(router_my_exit_policy_is_reject_star);
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, addr_is_invalid_dest)
-
/** Given that address is not a valid destination (as judged by
* address_is_invalid_destination() function), we want dns_resolve_impl()
* function to fail with return value -1.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star(void)
{
return 0;
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_addr_is_invalid_dest(void *arg)
{
int retval;
int made_pending;
@@ -436,7 +484,8 @@ NS(test_main)(void *arg)
(void)arg;
- NS_MOCK(router_my_exit_policy_is_reject_star);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star);
TO_CONN(exitconn)->address = tor_strdup("invalid#@!.org");
@@ -446,29 +495,25 @@ NS(test_main)(void *arg)
tt_int_op(retval,OP_EQ,-1);
done:
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(router_my_exit_policy_is_reject_star);
tor_free(TO_CONN(exitconn)->address);
tor_free(exitconn);
tor_free(on_circ);
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, malformed_ptr)
-
/** Given that address is a malformed PTR name, we want dns_resolve_impl to
* fail.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star(void)
{
return 0;
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_malformed_ptr(void *arg)
{
int retval;
int made_pending;
@@ -480,7 +525,8 @@ NS(test_main)(void *arg)
TO_CONN(exitconn)->address = tor_strdup("1.0.0.127.in-addr.arpa");
- NS_MOCK(router_my_exit_policy_is_reject_star);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star);
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
NULL);
@@ -498,30 +544,26 @@ NS(test_main)(void *arg)
tt_int_op(retval,OP_EQ,-1);
done:
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(router_my_exit_policy_is_reject_star);
tor_free(TO_CONN(exitconn)->address);
tor_free(exitconn);
tor_free(on_circ);
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, cache_hit_pending)
-
/* Given that there is already a pending resolve for the given address,
* we want dns_resolve_impl to append our exit connection to list
* of pending connections for the pending DNS request and return 0.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star(void)
{
return 0;
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_cache_hit_pending(void *arg)
{
int retval;
int made_pending = 0;
@@ -544,7 +586,8 @@ NS(test_main)(void *arg)
strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
sizeof(cache_entry->address));
- NS_MOCK(router_my_exit_policy_is_reject_star);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star);
dns_init();
@@ -562,7 +605,7 @@ NS(test_main)(void *arg)
tt_assert(pending_conn->conn == exitconn);
done:
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(router_my_exit_policy_is_reject_star);
tor_free(on_circ);
tor_free(TO_CONN(exitconn)->address);
tor_free(cache_entry->pending_connections);
@@ -571,16 +614,12 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, cache_hit_cached)
-
/* Given that a finished DNS resolve is available in our cache, we want
* dns_resolve_impl() return it to called via resolve_out and pass the
* handling to set_exitconn_info_from_resolve function.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star(void)
{
return 0;
}
@@ -589,7 +628,8 @@ static edge_connection_t *last_exitconn = NULL;
static cached_resolve_t *last_resolve = NULL;
static int
-NS(set_exitconn_info_from_resolve)(edge_connection_t *exitconn,
+dns_impl_cache_hit_cached_set_exitconn_info_from_resolve(
+ edge_connection_t *exitconn,
const cached_resolve_t *resolve,
char **hostname_out)
{
@@ -602,7 +642,7 @@ NS(set_exitconn_info_from_resolve)(edge_connection_t *exitconn,
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_cache_hit_cached(void *arg)
{
int retval;
int made_pending = 0;
@@ -625,8 +665,10 @@ NS(test_main)(void *arg)
strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
sizeof(cache_entry->address));
- NS_MOCK(router_my_exit_policy_is_reject_star);
- NS_MOCK(set_exitconn_info_from_resolve);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star);
+ MOCK(set_exitconn_info_from_resolve,
+ dns_impl_cache_hit_cached_set_exitconn_info_from_resolve);
dns_init();
@@ -643,8 +685,8 @@ NS(test_main)(void *arg)
tt_assert(last_resolve == cache_entry);
done:
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
- NS_UNMOCK(set_exitconn_info_from_resolve);
+ UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(set_exitconn_info_from_resolve);
tor_free(on_circ);
tor_free(TO_CONN(exitconn)->address);
tor_free(cache_entry->pending_connections);
@@ -652,10 +694,6 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE ASPECT(resolve_impl, cache_miss)
-
/* Given that there are neither pending nor pre-cached resolve for a given
* address, we want dns_resolve_impl() to create a new cached_resolve_t
* object, mark it as pending, insert it into the cache, attach the exit
@@ -663,7 +701,7 @@ NS(test_main)(void *arg)
* with the cached_resolve_t object it created.
*/
static int
-NS(router_my_exit_policy_is_reject_star)(void)
+dns_impl_cache_miss_router_my_exit_policy_is_reject_star(void)
{
return 0;
}
@@ -671,7 +709,7 @@ NS(router_my_exit_policy_is_reject_star)(void)
static cached_resolve_t *last_launched_resolve = NULL;
static int
-NS(launch_resolve)(cached_resolve_t *resolve)
+dns_impl_cache_miss_launch_resolve(cached_resolve_t *resolve)
{
last_launched_resolve = resolve;
@@ -679,7 +717,7 @@ NS(launch_resolve)(cached_resolve_t *resolve)
}
static void
-NS(test_main)(void *arg)
+test_dns_impl_cache_miss(void *arg)
{
int retval;
int made_pending = 0;
@@ -698,8 +736,10 @@ NS(test_main)(void *arg)
strlcpy(query.address, TO_CONN(exitconn)->address, sizeof(query.address));
- NS_MOCK(router_my_exit_policy_is_reject_star);
- NS_MOCK(launch_resolve);
+ MOCK(router_my_exit_policy_is_reject_star,
+ dns_impl_cache_miss_router_my_exit_policy_is_reject_star);
+ MOCK(launch_resolve,
+ dns_impl_cache_miss_launch_resolve);
dns_init();
@@ -722,8 +762,8 @@ NS(test_main)(void *arg)
tt_str_op(cache_entry->address,OP_EQ,TO_CONN(exitconn)->address);
done:
- NS_UNMOCK(router_my_exit_policy_is_reject_star);
- NS_UNMOCK(launch_resolve);
+ UNMOCK(router_my_exit_policy_is_reject_star);
+ UNMOCK(launch_resolve);
tor_free(on_circ);
tor_free(TO_CONN(exitconn)->address);
if (cache_entry)
@@ -733,19 +773,22 @@ NS(test_main)(void *arg)
return;
}
-#undef NS_SUBMODULE
-
struct testcase_t dns_tests[] = {
- TEST_CASE(clip_ttl),
- TEST_CASE(resolve),
- TEST_CASE_ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve),
- TEST_CASE_ASPECT(resolve_impl, non_exit),
- TEST_CASE_ASPECT(resolve_impl, addr_is_invalid_dest),
- TEST_CASE_ASPECT(resolve_impl, malformed_ptr),
- TEST_CASE_ASPECT(resolve_impl, cache_hit_pending),
- TEST_CASE_ASPECT(resolve_impl, cache_hit_cached),
- TEST_CASE_ASPECT(resolve_impl, cache_miss),
+#ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR
+ { "configure_ns_fallback", test_dns_configure_ns_fallback,
+ TT_FORK, NULL, NULL },
+#endif
+ { "clip_ttl", test_dns_clip_ttl, TT_FORK, NULL, NULL },
+ { "resolve", test_dns_resolve, TT_FORK, NULL, NULL },
+ { "impl_addr_is_ip", test_dns_impl_addr_is_ip, TT_FORK, NULL, NULL },
+ { "impl_non_exit", test_dns_impl_non_exit, TT_FORK, NULL, NULL },
+ { "impl_addr_is_invalid_dest", test_dns_impl_addr_is_invalid_dest,
+ TT_FORK, NULL, NULL },
+ { "impl_malformed_ptr", test_dns_impl_malformed_ptr, TT_FORK, NULL, NULL },
+ { "impl_cache_hit_pending", test_dns_impl_cache_hit_pending,
+ TT_FORK, NULL, NULL },
+ { "impl_cache_hit_cached", test_dns_impl_cache_hit_cached,
+ TT_FORK, NULL, NULL },
+ { "impl_cache_miss", test_dns_impl_cache_miss, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
-
-#undef NS_MODULE
diff --git a/src/test/test_dos.c b/src/test/test_dos.c
index 01d7cd006e..850bbef59b 100644
--- a/src/test/test_dos.c
+++ b/src/test/test_dos.c
@@ -1,8 +1,8 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DOS_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CIRCUITLIST_PRIVATE
#include "core/or/or.h"
@@ -66,9 +66,9 @@ test_dos_conn_creation(void *arg)
/* Initialize test data */
or_connection_t or_conn;
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr,
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr,
"18.0.0.1"));
- tor_addr_t *addr = &or_conn.real_addr;
+ tor_addr_t *addr = &TO_CONN(&or_conn)->addr;
/* Get DoS subsystem limits */
dos_init();
@@ -108,7 +108,7 @@ test_dos_conn_creation(void *arg)
/** Helper mock: Place a fake IP addr for this channel in <b>addr_out</b> */
static int
-mock_channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out)
+mock_channel_get_addr_if_possible(const channel_t *chan, tor_addr_t *addr_out)
{
(void)chan;
tt_int_op(AF_INET,OP_EQ, tor_addr_parse(addr_out, "18.0.0.1"));
@@ -139,9 +139,9 @@ test_dos_circuit_creation(void *arg)
/* Initialize test data */
or_connection_t or_conn;
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr,
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr,
"18.0.0.1"));
- tor_addr_t *addr = &or_conn.real_addr;
+ tor_addr_t *addr = &TO_CONN(&or_conn)->addr;
/* Get DoS subsystem limits */
dos_init();
@@ -202,9 +202,9 @@ test_dos_bucket_refill(void *arg)
channel_init(chan);
chan->is_client = 1;
or_connection_t or_conn;
- tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr,
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr,
"18.0.0.1"));
- tor_addr_t *addr = &or_conn.real_addr;
+ tor_addr_t *addr = &TO_CONN(&or_conn)->addr;
/* Initialize DoS subsystem and get relevant limits */
dos_init();
@@ -411,7 +411,7 @@ test_dos_bucket_refill(void *arg)
}
tt_uint_op(current_circ_count, OP_EQ, 0);
tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count);
-#endif
+#endif /* SIZEOF_TIME_T == 8 */
done:
tor_free(chan);
@@ -443,10 +443,10 @@ test_known_relay(void *arg)
/* Setup an OR conn so we can pass it to the DoS subsystem. */
or_connection_t or_conn;
- tor_addr_parse(&or_conn.real_addr, "42.42.42.42");
+ tor_addr_parse(&TO_CONN(&or_conn)->addr, "42.42.42.42");
rs = tor_malloc_zero(sizeof(*rs));
- rs->addr = tor_addr_to_ipv4h(&or_conn.real_addr);
+ tor_addr_copy(&rs->ipv4_addr, &TO_CONN(&or_conn)->addr);
crypto_rand(rs->identity_digest, sizeof(rs->identity_digest));
smartlist_add(dummy_ns->routerstatus_list, rs);
@@ -457,7 +457,8 @@ test_known_relay(void *arg)
/* We have now a node in our list so we'll make sure we don't count it as a
* client connection. */
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &TO_CONN(&or_conn)->addr,
+ NULL, 0);
/* Suppose we have 5 connections in rapid succession, the counter should
* always be 0 because we should ignore this. */
dos_new_client_conn(&or_conn, NULL);
@@ -465,18 +466,21 @@ test_known_relay(void *arg)
dos_new_client_conn(&or_conn, NULL);
dos_new_client_conn(&or_conn, NULL);
dos_new_client_conn(&or_conn, NULL);
- entry = geoip_lookup_client(&or_conn.real_addr, NULL, GEOIP_CLIENT_CONNECT);
+ entry = geoip_lookup_client(&TO_CONN(&or_conn)->addr, NULL,
+ GEOIP_CLIENT_CONNECT);
tt_assert(entry);
/* We should have a count of 0. */
tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 0);
/* To make sure that his is working properly, make a unknown client
* connection and see if we do get it. */
- tor_addr_parse(&or_conn.real_addr, "42.42.42.43");
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0);
+ tor_addr_parse(&TO_CONN(&or_conn)->addr, "42.42.42.43");
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &TO_CONN(&or_conn)->addr,
+ NULL, 0);
dos_new_client_conn(&or_conn, NULL);
dos_new_client_conn(&or_conn, NULL);
- entry = geoip_lookup_client(&or_conn.real_addr, NULL, GEOIP_CLIENT_CONNECT);
+ entry = geoip_lookup_client(&TO_CONN(&or_conn)->addr, NULL,
+ GEOIP_CLIENT_CONNECT);
tt_assert(entry);
/* We should have a count of 2. */
tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 2);
diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c
index fec0441234..75018260f7 100644
--- a/src/test/test_entryconn.c
+++ b/src/test/test_entryconn.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -11,7 +11,7 @@
#include "feature/client/addressmap.h"
#include "app/config/config.h"
-#include "app/config/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
#include "feature/nodelist/nodelist.h"
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index a486b13ae1..589876db2a 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -1,10 +1,11 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define CIRCUITLIST_PRIVATE
#define CIRCUITBUILD_PRIVATE
+#define CONFIG_PRIVATE
#define STATEFILE_PRIVATE
#define ENTRYNODES_PRIVATE
#define ROUTERLIST_PRIVATE
@@ -17,7 +18,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuitbuild.h"
#include "app/config/config.h"
-#include "app/config/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "feature/dircommon/directory.h"
#include "feature/dirclient/dirclient.h"
@@ -67,7 +68,7 @@ static networkstatus_t *dummy_consensus = NULL;
static smartlist_t *big_fake_net_nodes = NULL;
-static smartlist_t *
+static const smartlist_t *
bfn_mock_nodelist_get_list(void)
{
return big_fake_net_nodes;
@@ -127,6 +128,9 @@ big_fake_network_cleanup(const struct testcase_t *testcase, void *ptr)
return 1; /* NOP */
}
+#define REASONABLY_FUTURE " reasonably-future"
+#define REASONABLY_PAST " reasonably-past"
+
/* Unittest setup function: Setup a fake network. */
static void *
big_fake_network_setup(const struct testcase_t *testcase)
@@ -138,9 +142,10 @@ big_fake_network_setup(const struct testcase_t *testcase)
const int N_NODES = 271;
const char *argument = testcase->setup_data;
- int reasonably_live_consensus = 0;
+ int reasonably_future_consensus = 0, reasonably_past_consensus = 0;
if (argument) {
- reasonably_live_consensus = strstr(argument, "reasonably-live") != NULL;
+ reasonably_future_consensus = strstr(argument, REASONABLY_FUTURE) != NULL;
+ reasonably_past_consensus = strstr(argument, REASONABLY_PAST) != NULL;
}
big_fake_net_nodes = smartlist_new();
@@ -166,8 +171,8 @@ big_fake_network_setup(const struct testcase_t *testcase)
/* Note: all these guards have the same address, so you'll need to
* disable EnforceDistinctSubnets when a restriction is applied. */
- n->rs->addr = 0x04020202;
- n->rs->or_port = 1234;
+ tor_addr_from_ipv4h(&n->rs->ipv4_addr, 0x04020202);
+ n->rs->ipv4_orport = 1234;
n->rs->is_v2_dir = 1;
n->rs->has_bandwidth = 1;
n->rs->bandwidth_kb = 30;
@@ -193,16 +198,21 @@ big_fake_network_setup(const struct testcase_t *testcase)
n->md->exit_policy = parse_short_policy("accept 443");
}
+ n->nodelist_idx = smartlist_len(big_fake_net_nodes);
smartlist_add(big_fake_net_nodes, n);
}
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
dummy_consensus = tor_malloc_zero(sizeof(networkstatus_t));
- if (reasonably_live_consensus) {
- /* Make the dummy consensus valid from 4 hours ago, but expired an hour
+ if (reasonably_future_consensus) {
+ /* Make the dummy consensus valid in 6 hours, and expiring in 7 hours. */
+ dummy_consensus->valid_after = approx_time() + 6*3600;
+ dummy_consensus->valid_until = approx_time() + 7*3600;
+ } else if (reasonably_past_consensus) {
+ /* Make the dummy consensus valid from 16 hours ago, but expired 12 hours
* ago. */
- dummy_consensus->valid_after = approx_time() - 4*3600;
- dummy_consensus->valid_until = approx_time() - 3600;
+ dummy_consensus->valid_after = approx_time() - 16*3600;
+ dummy_consensus->valid_until = approx_time() - 12*3600;
} else {
/* Make the dummy consensus valid for an hour either side of now. */
dummy_consensus->valid_after = approx_time() - 3600;
@@ -226,12 +236,12 @@ mock_randomize_time_no_randomization(time_t a, time_t b)
return a;
}
-static or_options_t mocked_options;
+static or_options_t *mocked_options;
static const or_options_t *
mock_get_options(void)
{
- return &mocked_options;
+ return mocked_options;
}
#define TEST_IPV4_ADDR "123.45.67.89"
@@ -250,7 +260,7 @@ test_node_preferred_orport(void *arg)
tor_addr_port_t ap;
/* Setup options */
- memset(&mocked_options, 0, sizeof(mocked_options));
+ mocked_options = options_new();
/* We don't test ClientPreferIPv6ORPort here, because it's used in
* nodelist_set_consensus to setup node.ipv6_preferred, which we set
* directly. */
@@ -262,8 +272,8 @@ test_node_preferred_orport(void *arg)
/* Setup node_ri */
memset(&node_ri, 0, sizeof(node_ri));
- node_ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
- node_ri.or_port = ipv4_port;
+ tor_addr_copy(&node_ri.ipv4_addr, &ipv4_addr);
+ node_ri.ipv4_orport = ipv4_port;
tor_addr_copy(&node_ri.ipv6_addr, &ipv6_addr);
node_ri.ipv6_orport = ipv6_port;
@@ -273,8 +283,8 @@ test_node_preferred_orport(void *arg)
/* Check the preferred address is IPv4 if we're only using IPv4, regardless
* of whether we prefer it or not */
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 0;
+ mocked_options->ClientUseIPv4 = 1;
+ mocked_options->ClientUseIPv6 = 0;
node.ipv6_preferred = 0;
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
@@ -287,8 +297,8 @@ test_node_preferred_orport(void *arg)
/* Check the preferred address is IPv4 if we're using IPv4 and IPv6, but
* don't prefer the IPv6 address */
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 1;
+ mocked_options->ClientUseIPv4 = 1;
+ mocked_options->ClientUseIPv6 = 1;
node.ipv6_preferred = 0;
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
@@ -296,28 +306,29 @@ test_node_preferred_orport(void *arg)
/* Check the preferred address is IPv6 if we prefer it and
* ClientUseIPv6 is 1, regardless of ClientUseIPv4 */
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 1;
+ mocked_options->ClientUseIPv4 = 1;
+ mocked_options->ClientUseIPv6 = 1;
node.ipv6_preferred = 1;
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
tt_assert(ap.port == ipv6_port);
- mocked_options.ClientUseIPv4 = 0;
+ mocked_options->ClientUseIPv4 = 0;
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
tt_assert(ap.port == ipv6_port);
/* Check the preferred address is IPv6 if we don't prefer it, but
* ClientUseIPv4 is 0 */
- mocked_options.ClientUseIPv4 = 0;
- mocked_options.ClientUseIPv6 = 1;
- node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(&mocked_options);
+ mocked_options->ClientUseIPv4 = 0;
+ mocked_options->ClientUseIPv6 = 1;
+ node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(mocked_options);
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
tt_assert(ap.port == ipv6_port);
done:
+ or_options_free(mocked_options);
UNMOCK(get_options);
}
@@ -379,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:
@@ -410,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 "
@@ -421,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 "
@@ -610,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));
@@ -718,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);
@@ -973,10 +1002,10 @@ test_entry_guard_node_filter(void *arg)
g[1]->pb.path_bias_disabled = 1;
/* 2: Unreachable address. */
- n[2]->rs->addr = 0;
+ tor_addr_make_unspec(&n[2]->rs->ipv4_addr);
/* 3: ExcludeNodes */
- n[3]->rs->addr = 0x90902020;
+ tor_addr_from_ipv4h(&n[3]->rs->ipv4_addr, 0x90902020);
routerset_free(get_options_mutable()->ExcludeNodes);
get_options_mutable()->ExcludeNodes = routerset_new();
routerset_parse(get_options_mutable()->ExcludeNodes, "144.144.0.0/16", "");
@@ -985,8 +1014,8 @@ test_entry_guard_node_filter(void *arg)
get_options_mutable()->UseBridges = 1;
sweep_bridge_list();
bl = tor_malloc_zero(sizeof(bridge_line_t));
- tor_addr_from_ipv4h(&bl->addr, n[4]->rs->addr);
- bl->port = n[4]->rs->or_port;
+ tor_addr_copy(&bl->addr, &n[4]->rs->ipv4_addr);
+ bl->port = n[4]->rs->ipv4_orport;
memcpy(bl->digest, n[4]->identity, 20);
bridge_add_from_config(bl);
bl = NULL; // prevent free.
@@ -1095,7 +1124,7 @@ test_entry_guard_expand_sample(void *arg)
routerset_parse(get_options_mutable()->ExcludeNodes, "144.144.0.0/16", "");
SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, {
if (n_sl_idx % 64 != 0) {
- n->rs->addr = 0x90903030;
+ tor_addr_from_ipv4h(&n->rs->ipv4_addr, 0x90903030);
}
});
entry_guards_update_filtered_sets(gs);
@@ -1133,7 +1162,7 @@ test_entry_guard_expand_sample_small_net(void *arg)
test_node_free(n);
SMARTLIST_DEL_CURRENT(big_fake_net_nodes, n);
} else {
- n->rs->addr = 0; // make the filter reject this.
+ tor_addr_make_unspec(&n->rs->ipv4_addr); // make the filter reject this.
}
});
@@ -1450,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. */
@@ -1463,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
@@ -1481,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);
@@ -1499,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.
@@ -1536,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
@@ -1573,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:
@@ -1664,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) {
@@ -1683,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);
@@ -1782,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. */
@@ -3028,6 +3095,7 @@ static const struct testcase_setup_t upgrade_circuits = {
upgrade_circuits_setup, upgrade_circuits_cleanup
};
+#ifndef COCCI
#define NO_PREFIX_TEST(name) \
{ #name, test_ ## name, 0, NULL, NULL }
@@ -3039,13 +3107,18 @@ static const struct testcase_setup_t upgrade_circuits = {
#define BFN_TEST(name) \
EN_TEST_BASE(name, TT_FORK, &big_fake_network, NULL), \
- { #name "_reasonably_live", test_entry_guard_ ## name, TT_FORK, \
- &big_fake_network, (void*)("reasonably-live") }
+ { #name "_reasonably_future", test_entry_guard_ ## name, TT_FORK, \
+ &big_fake_network, (void*)(REASONABLY_FUTURE) }, \
+ { #name "_reasonably_past", test_entry_guard_ ## name, TT_FORK, \
+ &big_fake_network, (void*)(REASONABLY_PAST) }
#define UPGRADE_TEST(name, arg) \
EN_TEST_BASE(name, TT_FORK, &upgrade_circuits, arg), \
- { #name "_reasonably_live", test_entry_guard_ ## name, TT_FORK, \
- &upgrade_circuits, (void*)(arg " reasonably-live") }
+ { #name "_reasonably_future", test_entry_guard_ ## name, TT_FORK, \
+ &upgrade_circuits, (void*)(arg REASONABLY_FUTURE) }, \
+ { #name "_reasonably_past", test_entry_guard_ ## name, TT_FORK, \
+ &upgrade_circuits, (void*)(arg REASONABLY_PAST) }
+#endif /* !defined(COCCI) */
struct testcase_t entrynodes_tests[] = {
NO_PREFIX_TEST(node_preferred_orport),
@@ -3077,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_extorport.c b/src/test/test_extorport.c
index 0c34d37a71..7935530653 100644
--- a/src/test/test_extorport.c
+++ b/src/test/test_extorport.c
@@ -1,15 +1,15 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
#define EXT_ORPORT_PRIVATE
#define MAINLOOP_PRIVATE
#include "core/or/or.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_or.h"
#include "app/config/config.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "feature/relay/ext_orport.h"
#include "core/mainloop/mainloop.h"
@@ -18,6 +18,7 @@
#include "test/test.h"
#include "test/test_helpers.h"
+#include "test/rng_test_helpers.h"
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
@@ -176,7 +177,7 @@ test_ext_or_init_auth(void *arg)
/* Shouldn't be initialized already, or our tests will be a bit
* meaningless */
ext_or_auth_cookie = tor_malloc_zero(32);
- tt_assert(tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
+ tt_assert(fast_mem_is_zero((char*)ext_or_auth_cookie, 32));
/* Now make sure we use a temporary file */
fn = get_fname("ext_cookie_file");
@@ -201,7 +202,7 @@ test_ext_or_init_auth(void *arg)
tt_mem_op(cp,OP_EQ, "! Extended ORPort Auth Cookie !\x0a", 32);
tt_mem_op(cp+32,OP_EQ, ext_or_auth_cookie, 32);
memcpy(cookie0, ext_or_auth_cookie, 32);
- tt_assert(!tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
+ tt_assert(!fast_mem_is_zero((char*)ext_or_auth_cookie, 32));
/* Operation should be idempotent. */
tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
@@ -303,16 +304,6 @@ test_ext_or_cookie_auth(void *arg)
}
static void
-crypto_rand_return_tse_str(char *to, size_t n)
-{
- if (n != 32) {
- TT_FAIL(("Asked for %d bytes, not 32", (int)n));
- return;
- }
- memcpy(to, "te road There is always another ", 32);
-}
-
-static void
test_ext_or_cookie_auth_testvec(void *arg)
{
char *reply=NULL, *client_hash=NULL;
@@ -326,7 +317,7 @@ test_ext_or_cookie_auth_testvec(void *arg)
memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
ext_or_auth_cookie_is_set = 1;
- MOCK(crypto_rand, crypto_rand_return_tse_str);
+ testing_enable_prefilled_rng("te road There is always another ", 32);
tt_int_op(0, OP_EQ,
handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
@@ -351,7 +342,7 @@ test_ext_or_cookie_auth_testvec(void *arg)
"33b3cd77ff79bd80c2074bbf438119a2");
done:
- UNMOCK(crypto_rand);
+ testing_disable_prefilled_rng();
tor_free(reply);
tor_free(client_hash);
tor_free(mem_op_hex_tmp);
@@ -414,9 +405,9 @@ do_ext_or_handshake(or_connection_t *conn)
CONTAINS("\x01\x00", 2);
WRITE("\x01", 1);
WRITE("But when I look ahead up the whi", 32);
- MOCK(crypto_rand, crypto_rand_return_tse_str);
+ testing_enable_prefilled_rng("te road There is always another ", 32);
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
- UNMOCK(crypto_rand);
+ testing_disable_prefilled_rng();
tt_int_op(TO_CONN(conn)->state, OP_EQ,
EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH);
CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
@@ -481,9 +472,9 @@ test_ext_or_handshake(void *arg)
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
/* send the rest of the nonce. */
WRITE("ahead up the whi", 16);
- MOCK(crypto_rand, crypto_rand_return_tse_str);
+ testing_enable_prefilled_rng("te road There is always another ", 32);
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
- UNMOCK(crypto_rand);
+ testing_disable_prefilled_rng();
/* We should get the right reply from the server. */
CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
"\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
@@ -582,7 +573,7 @@ test_ext_or_handshake(void *arg)
done:
UNMOCK(connection_write_to_buf_impl_);
- UNMOCK(crypto_rand);
+ testing_disable_prefilled_rng();
if (conn)
connection_free_minimal(TO_CONN(conn));
#undef CONTAINS
@@ -596,6 +587,6 @@ struct testcase_t extorport_tests[] = {
{ "cookie_auth", test_ext_or_cookie_auth, TT_FORK, NULL, NULL },
{ "cookie_auth_testvec", test_ext_or_cookie_auth_testvec, TT_FORK,
NULL, NULL },
- { "handshake", test_ext_or_handshake, TT_FORK, NULL, NULL },
+ { "handshake", test_ext_or_handshake, TT_FORK, &helper_pubsub_setup, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_geoip.c b/src/test/test_geoip.c
index 16c566bdbc..95afe4d6c4 100644
--- a/src/test/test_geoip.c
+++ b/src/test/test_geoip.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -402,7 +402,7 @@ test_geoip_load_file(void *arg)
char *contents = NULL;
char *dhex = NULL;
- /* A nonexistant filename should fail. */
+ /* A nonexistent filename should fail. */
tt_int_op(-1, OP_EQ,
geoip_load_file(AF_INET, "/you/did/not/put/a/file/here/I/hope",
LOG_INFO));
@@ -412,7 +412,7 @@ test_geoip_load_file(void *arg)
tt_str_op("??", OP_EQ, geoip_get_country_name(0));
/* Any lookup attempt should say "-1" because we have no info */
tt_int_op(-1, OP_EQ, geoip_get_country_by_ipv4(0x01020304));
- /* There should be no 'digest' for a nonexistant file */
+ /* There should be no 'digest' for a nonexistent file */
tt_str_op("0000000000000000000000000000000000000000", OP_EQ,
geoip_db_digest(AF_INET));
@@ -467,7 +467,7 @@ test_geoip6_load_file(void *arg)
char *contents = NULL;
char *dhex = NULL;
- /* A nonexistant filename should fail. */
+ /* A nonexistent filename should fail. */
tt_int_op(-1, OP_EQ,
geoip_load_file(AF_INET6, "/you/did/not/put/a/file/here/I/hope",
LOG_INFO));
diff --git a/src/test/test_guardfraction.c b/src/test/test_guardfraction.c
index ac8bfbfded..6019dfc2b1 100644
--- a/src/test/test_guardfraction.c
+++ b/src/test/test_guardfraction.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define GUARDFRACTION_PRIVATE
@@ -51,9 +51,9 @@ gen_vote_routerstatus_for_tests(const char *digest_in_hex, int is_guard)
vrs->version = tor_strdup("0.1.2.14");
strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
memset(rs->descriptor_digest, 78, DIGEST_LEN);
- rs->addr = 0x99008801;
- rs->or_port = 443;
- rs->dir_port = 8000;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0x99008801);
+ rs->ipv4_orport = 443;
+ rs->ipv4_dirport = 8000;
/* all flags but running cleared */
rs->is_flagged_running = 1;
vrs->has_measured_bw = 1;
diff --git a/src/test/test_handles.c b/src/test/test_handles.c
index 7f1d6e1898..dbb5b1a18e 100644
--- a/src/test/test_handles.c
+++ b/src/test/test_handles.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index 802d0a9ebe..20d4582e74 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,42 +9,68 @@
#define ROUTERLIST_PRIVATE
#define CONFIG_PRIVATE
#define CONNECTION_PRIVATE
+#define CONNECTION_OR_PRIVATE
#define MAINLOOP_PRIVATE
#include "orconfig.h"
#include "core/or/or.h"
-#include "lib/container/buffers.h"
-#include "app/config/config.h"
-#include "app/config/confparse.h"
-#include "core/mainloop/connection.h"
+#include "lib/buf/buffers.h"
+#include "lib/confmgt/confmgt.h"
#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/dispatch/dispatch.h"
+#include "lib/dispatch/dispatch_naming.h"
+#include "lib/encoding/confline.h"
+#include "lib/net/resolve.h"
+#include "lib/pubsub/pubsub_build.h"
+#include "lib/pubsub/pubsub_connect.h"
+
+#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
-#include "feature/nodelist/nodelist.h"
+#include "core/or/connection_or.h"
+#include "core/or/crypt_path.h"
#include "core/or/relay.h"
+
+#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
-#include "lib/encoding/confline.h"
-#include "lib/net/resolve.h"
+
+#include "app/config/config.h"
+#include "app/main/subsysmgr.h"
#include "core/or/cell_st.h"
#include "core/or/connection_st.h"
-#include "feature/nodelist/node_st.h"
+#include "core/or/cpath_build_state_st.h"
+#include "core/or/crypt_path_st.h"
#include "core/or/origin_circuit_st.h"
+#include "core/or/or_connection_st.h"
+
+#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerlist_st.h"
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef _WIN32
+/* For mkdir() */
+#include <direct.h>
+#else
+#include <dirent.h>
+#endif /* defined(_WIN32) */
+
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/test_connection.h"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-DISABLE_GCC_WARNING(overlength-strings)
+DISABLE_GCC_WARNING("-Woverlength-strings")
/* We allow huge string constants in the unit tests, but not in the code
* at large. */
#endif
#include "test_descriptors.inc"
#include "core/or/circuitlist.h"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-ENABLE_GCC_WARNING(overlength-strings)
+ENABLE_GCC_WARNING("-Woverlength-strings")
#endif
/* Return a statically allocated string representing yesterday's date
@@ -78,7 +104,7 @@ helper_setup_fake_routerlist(void)
{
int retval;
routerlist_t *our_routerlist = NULL;
- smartlist_t *our_nodelist = NULL;
+ const smartlist_t *our_nodelist = NULL;
/* Read the file that contains our test descriptors. */
@@ -87,12 +113,17 @@ helper_setup_fake_routerlist(void)
MOCK(router_descriptor_is_older_than,
router_descriptor_is_older_than_replacement);
+ // Pick a time when these descriptors' certificates were valid.
+ update_approx_time(1603981036);
+
/* Load all the test descriptors to the routerlist. */
retval = router_load_routers_from_string(TEST_DESCRIPTORS,
NULL, SAVED_IN_JOURNAL,
NULL, 0, NULL);
tt_int_op(retval, OP_EQ, HELPER_NUMBER_OF_DESCRIPTORS);
+ update_approx_time(0); // this restores the regular approx_time behavior
+
/* Sanity checking of routerlist and nodelist. */
our_routerlist = router_get_routerlist();
tt_int_op(smartlist_len(our_routerlist->routers), OP_EQ,
@@ -179,6 +210,78 @@ mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
return tor_addr_lookup__real(name, family, out);
}
+static char *
+create_directory(const char *parent_dir, const char *name)
+{
+ char *dir = NULL;
+ tor_asprintf(&dir, "%s"PATH_SEPARATOR"%s", parent_dir, name);
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+ return dir;
+
+ done:
+ tor_free(dir);
+ return NULL;
+}
+
+static char *
+create_file(const char *parent_dir, const char *name, const char *contents)
+{
+ char *path = NULL;
+ tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", parent_dir, name);
+ contents = contents == NULL ? "" : contents;
+ tt_int_op(write_str_to_file(path, contents, 0), OP_EQ, 0);
+ return path;
+
+ done:
+ tor_free(path);
+ return NULL;
+}
+
+int
+create_test_directory_structure(const char *parent_dir)
+{
+ int ret = -1;
+ char *dir1 = NULL;
+ char *dir2 = NULL;
+ char *file1 = NULL;
+ char *file2 = NULL;
+ char *dot = NULL;
+ char *empty = NULL;
+ char *forbidden = NULL;
+
+ dir1 = create_directory(parent_dir, "dir1");
+ tt_assert(dir1);
+ dir2 = create_directory(parent_dir, "dir2");
+ tt_assert(dir2);
+ file1 = create_file(parent_dir, "file1", "Test 1");
+ tt_assert(file1);
+ file2 = create_file(parent_dir, "file2", "Test 2");
+ tt_assert(file2);
+ dot = create_file(parent_dir, ".test-hidden", "Test .");
+ tt_assert(dot);
+ empty = create_file(parent_dir, "empty", NULL);
+ tt_assert(empty);
+ forbidden = create_directory(parent_dir, "forbidden");
+ tt_assert(forbidden);
+#ifndef _WIN32
+ tt_int_op(chmod(forbidden, 0), OP_EQ, 0);
+#endif
+ ret = 0;
+ done:
+ tor_free(dir1);
+ tor_free(dir2);
+ tor_free(file1);
+ tor_free(file2);
+ tor_free(dot);
+ tor_free(empty);
+ tor_free(forbidden);
+ return ret;
+}
+
/*********** Helper funcs for making new connections/streams *****************/
/* Helper for test_conn_get_connection() */
@@ -189,6 +292,14 @@ fake_close_socket(tor_socket_t sock)
return 0;
}
+/* Helper for test_conn_get_proxy_or_connection() */
+void
+mock_connection_or_change_state(or_connection_t *conn, uint8_t state)
+{
+ tor_assert(conn);
+ conn->base_.state = state;
+}
+
static int mock_connection_connect_sockaddr_called = 0;
static int fake_socket_number = TEST_CONN_FD_INIT;
@@ -223,6 +334,77 @@ mock_connection_connect_sockaddr(connection_t *conn,
return 1;
}
+or_connection_t *
+test_conn_get_proxy_or_connection(unsigned int proxy_type)
+{
+ or_connection_t *conn = NULL;
+ tor_addr_t dst_addr;
+ tor_addr_t proxy_addr;
+ int socket_err = 0;
+ int in_progress = 0;
+
+ MOCK(connection_connect_sockaddr,
+ mock_connection_connect_sockaddr);
+ MOCK(connection_write_to_buf_impl_,
+ connection_write_to_buf_mock);
+ MOCK(connection_or_change_state,
+ mock_connection_or_change_state);
+ MOCK(tor_close_socket, fake_close_socket);
+
+ tor_init_connection_lists();
+
+ conn = or_connection_new(CONN_TYPE_OR, TEST_CONN_FAMILY);
+ tt_assert(conn);
+
+ /* Set up a destination address. */
+ test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY,
+ &dst_addr);
+ tt_assert(!tor_addr_is_null(&dst_addr));
+
+ conn->proxy_type = proxy_type;
+ conn->base_.proxy_state = PROXY_INFANT;
+
+ tor_addr_copy_tight(&conn->base_.addr, &dst_addr);
+ conn->base_.address = tor_addr_to_str_dup(&dst_addr);
+ conn->base_.port = TEST_CONN_PORT;
+
+ /* Set up a proxy address. */
+ test_conn_lookup_addr_helper(TEST_CONN_ADDRESS_2, TEST_CONN_FAMILY,
+ &proxy_addr);
+ tt_assert(!tor_addr_is_null(&proxy_addr));
+
+ conn->base_.state = OR_CONN_STATE_CONNECTING;
+
+ mock_connection_connect_sockaddr_called = 0;
+ in_progress = connection_connect(TO_CONN(conn), TEST_CONN_ADDRESS_PORT,
+ &proxy_addr, TEST_CONN_PORT, &socket_err);
+ tt_int_op(mock_connection_connect_sockaddr_called, OP_EQ, 1);
+ tt_assert(!socket_err);
+ tt_assert(in_progress == 0 || in_progress == 1);
+
+ assert_connection_ok(TO_CONN(conn), time(NULL));
+
+ in_progress = connection_or_finished_connecting(conn);
+ tt_int_op(in_progress, OP_EQ, 0);
+
+ assert_connection_ok(TO_CONN(conn), time(NULL));
+
+ UNMOCK(connection_connect_sockaddr);
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(connection_or_change_state);
+ UNMOCK(tor_close_socket);
+ return conn;
+
+ /* On failure */
+ done:
+ UNMOCK(connection_connect_sockaddr);
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(connection_or_change_state);
+ UNMOCK(tor_close_socket);
+ connection_free_(TO_CONN(conn));
+ return NULL;
+}
+
/** Create and return a new connection/stream */
connection_t *
test_conn_get_connection(uint8_t state, uint8_t type, uint8_t purpose)
@@ -290,7 +472,7 @@ helper_parse_options(const char *conf)
if (ret != 0) {
goto done;
}
- ret = config_assign(&options_format, opt, line, 0, &msg);
+ ret = config_assign(get_options_mgr(), opt, line, 0, &msg);
if (ret != 0) {
goto done;
}
@@ -303,3 +485,87 @@ helper_parse_options(const char *conf)
}
return opt;
}
+
+/**
+ * Dispatch alertfn callback: flush all messages right now. Implements
+ * DELIV_IMMEDIATE.
+ **/
+static void
+alertfn_immediate(dispatch_t *d, channel_id_t chan, void *arg)
+{
+ (void) arg;
+ dispatch_flush(d, chan, INT_MAX);
+}
+
+/**
+ * Setup helper for tests that need pubsub active
+ *
+ * Does not hook up mainloop events. Does set immediate delivery for
+ * all channels.
+ */
+void *
+helper_setup_pubsub(const struct testcase_t *testcase)
+{
+ dispatch_t *dispatcher = NULL;
+ pubsub_builder_t *builder = pubsub_builder_new();
+ channel_id_t chan = get_channel_id("orconn");
+
+ (void)testcase;
+ (void)subsystems_add_pubsub(builder);
+ dispatcher = pubsub_builder_finalize(builder, NULL);
+ tor_assert(dispatcher);
+ dispatch_set_alert_fn(dispatcher, chan, alertfn_immediate, NULL);
+ chan = get_channel_id("ocirc");
+ dispatch_set_alert_fn(dispatcher, chan, alertfn_immediate, NULL);
+ return dispatcher;
+}
+
+/**
+ * Cleanup helper for tests that need pubsub active
+ */
+int
+helper_cleanup_pubsub(const struct testcase_t *testcase, void *dispatcher_)
+{
+ dispatch_t *dispatcher = dispatcher_;
+
+ (void)testcase;
+ dispatch_free(dispatcher);
+ return 1;
+}
+
+const struct testcase_setup_t helper_pubsub_setup = {
+ helper_setup_pubsub, helper_cleanup_pubsub
+};
+
+origin_circuit_t *
+new_test_origin_circuit(bool has_opened,
+ struct timeval circ_start_time,
+ int path_len,
+ extend_info_t **ei_list)
+{
+ origin_circuit_t *origin_circ = origin_circuit_new();
+
+ TO_CIRCUIT(origin_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ origin_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ origin_circ->build_state->desired_path_len = path_len;
+
+ if (ei_list) {
+ for (int i = 0; i < path_len; i++) {
+ extend_info_t *ei = ei_list[i];
+ cpath_append_hop(&origin_circ->cpath, ei);
+ }
+ }
+
+ if (has_opened) {
+ origin_circ->has_opened = 1;
+ TO_CIRCUIT(origin_circ)->state = CIRCUIT_STATE_OPEN;
+ origin_circ->cpath->state = CPATH_STATE_OPEN;
+ } else {
+ TO_CIRCUIT(origin_circ)->timestamp_began = circ_start_time;
+ TO_CIRCUIT(origin_circ)->timestamp_created = circ_start_time;
+ origin_circ->cpath->state = CPATH_STATE_CLOSED;
+ }
+
+ return origin_circ;
+}
diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h
index 9e376a563d..f02ecbb0ac 100644
--- a/src/test/test_helpers.h
+++ b/src/test/test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_HELPERS_H
@@ -7,6 +7,7 @@
#define BUFFERS_PRIVATE
#include "core/or/or.h"
+#include "tinytest.h"
const char *get_yesterday_date_str(void);
@@ -25,11 +26,26 @@ char *buf_get_contents(buf_t *buf, size_t *sz_out);
int mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
uint16_t family, tor_addr_t *out);
+void mock_connection_or_change_state(or_connection_t *conn, uint8_t state);
+
+or_connection_t *test_conn_get_proxy_or_connection(unsigned int proxy_type);
connection_t *test_conn_get_connection(uint8_t state,
uint8_t type, uint8_t purpose);
or_options_t *helper_parse_options(const char *conf);
+int create_test_directory_structure(const char *parent_dir);
+
extern const char TEST_DESCRIPTORS[];
+void *helper_setup_pubsub(const struct testcase_t *);
+int helper_cleanup_pubsub(const struct testcase_t *, void *);
+
+extern const struct testcase_setup_t helper_pubsub_setup;
+
+origin_circuit_t *new_test_origin_circuit(bool has_opened,
+ struct timeval circ_start_time,
+ int path_len,
+ extend_info_t **ei_list);
+
#endif /* !defined(TOR_TEST_HELPERS_H) */
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
index a611b46ca6..46b4493a3d 100644
--- a/src/test/test_hs.c
+++ b/src/test/test_hs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,7 +6,7 @@
* \brief Unit tests for hidden service.
**/
-#define CONTROL_PRIVATE
+#define CONTROL_EVENTS_PRIVATE
#define CIRCUITBUILD_PRIVATE
#define RENDCOMMON_PRIVATE
#define RENDSERVICE_PRIVATE
@@ -15,6 +15,8 @@
#include "core/or/or.h"
#include "test/test.h"
#include "feature/control/control.h"
+#include "feature/control/control_events.h"
+#include "feature/control/control_fmt.h"
#include "app/config/config.h"
#include "feature/hs/hs_common.h"
#include "feature/rend/rendcommon.h"
@@ -321,6 +323,16 @@ test_hs_desc_event(void *arg)
tt_str_op(received_msg,OP_EQ, expected_msg);
tor_free(received_msg);
+ /* test HSDir rate limited */
+ rend_query.auth_type = REND_NO_AUTH;
+ control_event_hsv2_descriptor_failed(&rend_query.base_, NULL,
+ "QUERY_RATE_LIMITED");
+ expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \
+ "UNKNOWN REASON=QUERY_RATE_LIMITED\r\n";
+ tt_assert(received_msg);
+ tt_str_op(received_msg,OP_EQ, expected_msg);
+ tor_free(received_msg);
+
/* Test invalid content with no HSDir fingerprint. */
char *exp_msg;
control_event_hs_descriptor_content(rend_query.onion_address,
@@ -436,7 +448,7 @@ test_hs_rend_data(void *arg)
tt_int_op(client_v2->auth_type, OP_EQ, REND_BASIC_AUTH);
tt_int_op(strlen(client_v2->onion_address), OP_EQ, 0);
tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
- tt_int_op(tor_mem_is_zero(client_v2->descriptor_cookie,
+ tt_int_op(fast_mem_is_zero(client_v2->descriptor_cookie,
sizeof(client_v2->descriptor_cookie)), OP_EQ, 1);
tt_assert(client->hsdirs_fp);
tt_int_op(smartlist_len(client->hsdirs_fp), OP_EQ, 0);
diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c
index 742fa349d9..df96b2c791 100644
--- a/src/test/test_hs_cache.c
+++ b/src/test/test_hs_cache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,6 +10,7 @@
#define DIRCACHE_PRIVATE
#define DIRCLIENT_PRIVATE
#define HS_CACHE_PRIVATE
+#define CHANNEL_OBJECT_PRIVATE
#include "trunnel/ed25519_cert.h"
#include "feature/hs/hs_cache.h"
@@ -19,8 +20,14 @@
#include "feature/nodelist/networkstatus.h"
#include "core/mainloop/connection.h"
#include "core/proto/proto_http.h"
+#include "core/or/circuitlist.h"
+#include "core/or/channel.h"
#include "lib/crypt_ops/crypto_format.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "core/or/edge_connection_st.h"
+#include "core/or/or_circuit_st.h"
+#include "core/or/or_connection_st.h"
#include "feature/dircommon/dir_connection_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -232,22 +239,31 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key)
/* The dir conn we are going to simulate */
dir_connection_t *conn = NULL;
+ edge_connection_t *edge_conn = NULL;
+ or_circuit_t *or_circ = NULL;
/* First extract the blinded public key that we are going to use in our
query, and then build the actual query string. */
{
char hsdir_cache_key[ED25519_BASE64_LEN+1];
- retval = ed25519_public_to_base64(hsdir_cache_key,
- blinded_key);
- tt_int_op(retval, OP_EQ, 0);
+ ed25519_public_to_base64(hsdir_cache_key, blinded_key);
tor_asprintf(&hsdir_query_str, GET("/tor/hs/3/%s"), hsdir_cache_key);
}
/* Simulate an HTTP GET request to the HSDir */
conn = dir_connection_new(AF_INET);
+ tt_assert(conn);
+ TO_CONN(conn)->linked = 1; /* Signal that it is encrypted. */
tor_addr_from_ipv4h(&conn->base_.addr, 0x7f000001);
- TO_CONN(conn)->linked = 1;/* Pretend the conn is encrypted :) */
+
+ /* Pretend this conn is anonymous. */
+ edge_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
+ TO_CONN(conn)->linked_conn = TO_CONN(edge_conn);
+ or_circ = or_circuit_new(0, NULL);
+ or_circ->p_chan = tor_malloc_zero(sizeof(channel_t));
+ edge_conn->on_circuit = TO_CIRCUIT(or_circ);
+
retval = directory_handle_command_get(conn, hsdir_query_str,
NULL, 0);
tt_int_op(retval, OP_EQ, 0);
@@ -264,8 +280,11 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key)
done:
tor_free(hsdir_query_str);
- if (conn)
+ if (conn) {
+ tor_free(or_circ->p_chan);
+ connection_free_minimal(TO_CONN(conn)->linked_conn);
connection_free_minimal(TO_CONN(conn));
+ }
return received_desc;
}
@@ -351,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;
@@ -388,12 +407,12 @@ 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);
- tt_int_op(retval, OP_EQ, 0);
+ &subcredential, NULL, &received_desc);
+ tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(received_desc);
/* Check that the revision counter is correct */
@@ -425,8 +444,8 @@ 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);
- tt_int_op(retval, OP_EQ, 0);
+ &subcredential, NULL, &received_desc);
+ tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(received_desc);
/* Check that the revision counter is the latest */
@@ -458,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;
@@ -487,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(!tor_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() */
@@ -522,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 */
@@ -550,6 +572,136 @@ test_client_cache(void *arg)
}
}
+/** Test that we can store HS descriptors in the client HS cache. */
+static void
+test_client_cache_decrypt(void *arg)
+{
+ int ret;
+ char *desc_encoded = NULL;
+ uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
+ curve25519_keypair_t client_kp;
+ ed25519_keypair_t service_kp;
+ hs_descriptor_t *desc = NULL;
+ const hs_descriptor_t *search_desc;
+ const char *search_desc_encoded;
+
+ (void) arg;
+
+ /* Initialize HSDir cache subsystem */
+ hs_init();
+
+ MOCK(networkstatus_get_reasonably_live_consensus,
+ mock_networkstatus_get_reasonably_live_consensus);
+
+ /* Set consensus time */
+ parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
+ &mock_ns.valid_until);
+
+ /* Generate a valid descriptor with normal values. */
+ {
+ ret = ed25519_keypair_generate(&service_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = curve25519_keypair_generate(&client_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
+
+ desc = hs_helper_build_hs_desc_with_client_auth(descriptor_cookie,
+ &client_kp.pubkey,
+ &service_kp);
+ tt_assert(desc);
+ ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
+ &desc_encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Put it in the cache. Should not be decrypted since the client
+ * authorization creds were not added to the global map. */
+ ret = hs_cache_store_as_client(desc_encoded, &service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
+
+ /* We should not be able to decrypt anything. */
+ ret = hs_cache_client_new_auth_parse(&service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, false);
+
+ /* Add client auth to global map. */
+ hs_helper_add_client_auth(&service_kp.pubkey, &client_kp.seckey);
+
+ /* We should not be able to decrypt anything. */
+ ret = hs_cache_client_new_auth_parse(&service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, true);
+
+ /* Lookup the cache to make sure it is usable and there. */
+ search_desc = hs_cache_lookup_as_client(&service_kp.pubkey);
+ tt_assert(search_desc);
+ search_desc_encoded = hs_cache_lookup_encoded_as_client(&service_kp.pubkey);
+ tt_mem_op(search_desc_encoded, OP_EQ, desc_encoded, strlen(desc_encoded));
+
+ done:
+ hs_descriptor_free(desc);
+ tor_free(desc_encoded);
+
+ hs_free_all();
+
+ UNMOCK(networkstatus_get_reasonably_live_consensus);
+}
+
+static void
+test_client_cache_remove(void *arg)
+{
+ int ret;
+ ed25519_keypair_t service_kp;
+ hs_descriptor_t *desc1 = NULL;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(networkstatus_get_reasonably_live_consensus,
+ mock_networkstatus_get_reasonably_live_consensus);
+
+ /* Set consensus time. Lookup will not return the entry if it has expired
+ * and it is checked against the consensus valid_after time. */
+ parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
+ &mock_ns.valid_until);
+
+ /* Generate service keypair */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
+
+ /* Build a descriptor and cache it. */
+ {
+ char *encoded;
+ desc1 = hs_helper_build_hs_desc_with_ip(&service_kp);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(encoded);
+
+ /* Store it */
+ ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
+ tor_free(encoded);
+ tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
+ }
+
+ /* Remove the cached entry. */
+ hs_cache_remove_as_client(&service_kp.pubkey);
+ tt_assert(!hs_cache_lookup_as_client(&service_kp.pubkey));
+
+ done:
+ hs_descriptor_free(desc1);
+ hs_free_all();
+
+ UNMOCK(networkstatus_get_reasonably_live_consensus);
+}
+
struct testcase_t hs_cache[] = {
/* Encoding tests. */
{ "directory", test_directory, TT_FORK,
@@ -562,6 +714,10 @@ struct testcase_t hs_cache[] = {
NULL, NULL },
{ "client_cache", test_client_cache, TT_FORK,
NULL, NULL },
+ { "client_cache_decrypt", test_client_cache_decrypt, TT_FORK,
+ NULL, NULL },
+ { "client_cache_remove", test_client_cache_remove, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_cell.c b/src/test/test_hs_cell.c
index f8af631c8b..5406339276 100644
--- a/src/test/test_hs_cell.c
+++ b/src/test/test_hs_cell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,6 +20,7 @@
#include "feature/hs/hs_service.h"
/* Trunnel. */
+#include "trunnel/hs/cell_common.h"
#include "trunnel/hs/cell_establish_intro.h"
/** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we
@@ -38,11 +39,13 @@ test_gen_establish_intro_cell(void *arg)
/* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
attempt to parse it. */
{
+ hs_service_config_t config;
+ memset(&config, 0, sizeof(config));
/* We only need the auth key pair here. */
- hs_service_intro_point_t *ip = service_intro_point_new(NULL, 0, 0);
+ hs_service_intro_point_t *ip = service_intro_point_new(NULL);
/* Auth key pair is generated in the constructor so we are all set for
* using this IP object. */
- ret = hs_cell_build_establish_intro(circ_nonce, ip, buf);
+ ret = hs_cell_build_establish_intro(circ_nonce, &config, ip, buf);
service_intro_point_free(ip);
tt_u64_op(ret, OP_GT, 0);
}
@@ -97,6 +100,9 @@ test_gen_establish_intro_cell_bad(void *arg)
trn_cell_establish_intro_t *cell = NULL;
char circ_nonce[DIGEST_LEN] = {0};
hs_service_intro_point_t *ip = NULL;
+ hs_service_config_t config;
+
+ memset(&config, 0, sizeof(config));
MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed);
@@ -107,8 +113,8 @@ test_gen_establish_intro_cell_bad(void *arg)
ed25519_sign_prefixed() function and make it fail. */
cell = trn_cell_establish_intro_new();
tt_assert(cell);
- ip = service_intro_point_new(NULL, 0, 0);
- cell_len = hs_cell_build_establish_intro(circ_nonce, ip, NULL);
+ ip = service_intro_point_new(NULL);
+ cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, NULL);
service_intro_point_free(ip);
expect_log_msg_containing("Unable to make signature for "
"ESTABLISH_INTRO cell.");
@@ -120,11 +126,97 @@ test_gen_establish_intro_cell_bad(void *arg)
UNMOCK(ed25519_sign_prefixed);
}
+static void
+test_gen_establish_intro_dos_ext(void *arg)
+{
+ ssize_t ret;
+ hs_service_config_t config;
+ hs_service_intro_point_t *ip = NULL;
+ trn_cell_extension_t *extensions = NULL;
+ trn_cell_extension_dos_t *dos = NULL;
+
+ (void) arg;
+
+ memset(&config, 0, sizeof(config));
+ ip = service_intro_point_new(NULL);
+ tt_assert(ip);
+ ip->support_intro2_dos_defense = 1;
+
+ /* Case 1: No DoS parameters so no extension to be built. */
+ extensions = build_establish_intro_extensions(&config, ip);
+ tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 0);
+ trn_cell_extension_free(extensions);
+ extensions = NULL;
+
+ /* Case 2: Enable the DoS extension. Parameter set to 0 should indicate to
+ * disable the defense on the intro point but there should be an extension
+ * nonetheless in the cell. */
+ config.has_dos_defense_enabled = 1;
+ extensions = build_establish_intro_extensions(&config, ip);
+ tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 1);
+ /* Validate the extension. */
+ const trn_cell_extension_field_t *field =
+ trn_cell_extension_getconst_fields(extensions, 0);
+ tt_int_op(trn_cell_extension_field_get_field_type(field), OP_EQ,
+ TRUNNEL_CELL_EXTENSION_TYPE_DOS);
+ ret = trn_cell_extension_dos_parse(&dos,
+ trn_cell_extension_field_getconstarray_field(field),
+ trn_cell_extension_field_getlen_field(field));
+ tt_int_op(ret, OP_EQ, 19);
+ /* Rate per sec param. */
+ const trn_cell_extension_dos_param_t *param =
+ trn_cell_extension_dos_getconst_params(dos, 0);
+ tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ,
+ TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC);
+ tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 0);
+ /* Burst per sec param. */
+ param = trn_cell_extension_dos_getconst_params(dos, 1);
+ tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ,
+ TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC);
+ tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 0);
+ trn_cell_extension_dos_free(dos); dos = NULL;
+ trn_cell_extension_free(extensions); extensions = NULL;
+
+ /* Case 3: Enable the DoS extension. Parameter set to some normal values. */
+ config.has_dos_defense_enabled = 1;
+ config.intro_dos_rate_per_sec = 42;
+ config.intro_dos_burst_per_sec = 250;
+ extensions = build_establish_intro_extensions(&config, ip);
+ tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 1);
+ /* Validate the extension. */
+ field = trn_cell_extension_getconst_fields(extensions, 0);
+ tt_int_op(trn_cell_extension_field_get_field_type(field), OP_EQ,
+ TRUNNEL_CELL_EXTENSION_TYPE_DOS);
+ ret = trn_cell_extension_dos_parse(&dos,
+ trn_cell_extension_field_getconstarray_field(field),
+ trn_cell_extension_field_getlen_field(field));
+ tt_int_op(ret, OP_EQ, 19);
+ /* Rate per sec param. */
+ param = trn_cell_extension_dos_getconst_params(dos, 0);
+ tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ,
+ TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC);
+ tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 42);
+ /* Burst per sec param. */
+ param = trn_cell_extension_dos_getconst_params(dos, 1);
+ tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ,
+ TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC);
+ tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 250);
+ trn_cell_extension_dos_free(dos); dos = NULL;
+ trn_cell_extension_free(extensions); extensions = NULL;
+
+ done:
+ service_intro_point_free(ip);
+ trn_cell_extension_dos_free(dos);
+ trn_cell_extension_free(extensions);
+}
+
struct testcase_t hs_cell_tests[] = {
{ "gen_establish_intro_cell", test_gen_establish_intro_cell, TT_FORK,
NULL, NULL },
{ "gen_establish_intro_cell_bad", test_gen_establish_intro_cell_bad, TT_FORK,
NULL, NULL },
+ { "gen_establish_intro_dos_ext", test_gen_establish_intro_dos_ext, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index 53ee3c53d2..f59b3a59cd 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,10 +10,11 @@
#define CRYPTO_PRIVATE
#define MAINLOOP_PRIVATE
#define HS_CLIENT_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define CIRCUITBUILD_PRIVATE
#define CIRCUITLIST_PRIVATE
#define CONNECTION_PRIVATE
+#define CRYPT_PATH_PRIVATE
#include "test/test.h"
#include "test/test_helpers.h"
@@ -24,6 +25,7 @@
#include "app/config/config.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_dh.h"
+#include "lib/crypt_ops/crypto_rand.h"
#include "core/or/channeltls.h"
#include "feature/dircommon/directory.h"
#include "core/mainloop/mainloop.h"
@@ -36,14 +38,17 @@
#include "feature/hs/hs_config.h"
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_cache.h"
+#include "feature/rend/rendcache.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitbuild.h"
+#include "core/or/extendinfo.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
#include "feature/nodelist/networkstatus.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
+#include "core/or/crypt_path.h"
#include "feature/dircommon/dir_connection_st.h"
#include "core/or/entry_connection_st.h"
#include "core/or/extend_info_st.h"
@@ -78,6 +83,23 @@ mock_networkstatus_get_reasonably_live_consensus(time_t now, int flavor)
}
static int
+mock_write_str_to_file(const char *path, const char *str, int bin)
+{
+ (void) bin;
+ (void) path;
+ (void) str;
+ return 0;
+}
+
+static or_options_t mocked_options;
+
+static const or_options_t *
+mock_get_options(void)
+{
+ return &mocked_options;
+}
+
+static int
helper_config_client(const char *conf, int validate_only)
{
int ret = 0;
@@ -91,6 +113,24 @@ helper_config_client(const char *conf, int validate_only)
return ret;
}
+static void
+helper_add_random_client_auth(const ed25519_public_key_t *service_pk)
+{
+ char *conf = NULL;
+#define conf_fmt "ClientOnionAuthDir %s\n"
+ tor_asprintf(&conf, conf_fmt, get_fname("auth_keys"));
+#undef conf_fmt
+ helper_config_client(conf, 0);
+ tor_free(conf);
+
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ hs_client_service_authorization_t *auth =
+ tor_malloc_zero(sizeof(hs_client_service_authorization_t));
+ curve25519_secret_key_generate(&auth->enc_seckey, 0);
+ hs_build_address(service_pk, HS_VERSION_THREE, auth->onion_address);
+ digest256map_set(client_auths, service_pk->pubkey, auth);
+}
+
/* Test helper function: Setup a circuit and a stream with the same hidden
* service destination, and put them in <b>circ_out</b> and
* <b>conn_out</b>. Make the stream wait for circuits to be established to the
@@ -159,8 +199,7 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
or_circ->rend_data = rend_data_dup(conn_rend_data);
} else {
/* prop224: Setup hs ident on the circuit */
- or_circ->hs_ident = hs_ident_circuit_new(&service_pk,
- HS_IDENT_CIRCUIT_RENDEZVOUS);
+ or_circ->hs_ident = hs_ident_circuit_new(&service_pk);
}
TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
@@ -243,12 +282,14 @@ test_e2e_rend_circuit_setup_legacy(void *arg)
tt_int_op(retval, OP_EQ, 1);
/* Check the digest algo */
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.f_digest),
+ tt_int_op(
+ crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest),
OP_EQ, DIGEST_SHA1);
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.b_digest),
+ tt_int_op(
+ crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest),
OP_EQ, DIGEST_SHA1);
- tt_assert(or_circ->cpath->crypto.f_crypto);
- tt_assert(or_circ->cpath->crypto.b_crypto);
+ tt_assert(or_circ->cpath->pvt_crypto.f_crypto);
+ tt_assert(or_circ->cpath->pvt_crypto.b_crypto);
/* Ensure that circ purpose was changed */
tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
@@ -285,7 +326,7 @@ test_e2e_rend_circuit_setup(void *arg)
mock_connection_ap_handshake_send_begin);
/* Setup */
- retval = helper_get_circ_and_stream_for_test( &or_circ, &conn, 0);
+ retval = helper_get_circ_and_stream_for_test(&or_circ, &conn, 0);
tt_int_op(retval, OP_EQ, 0);
tt_assert(or_circ);
tt_assert(conn);
@@ -301,9 +342,8 @@ test_e2e_rend_circuit_setup(void *arg)
/**********************************************/
/* Setup the circuit */
- retval = hs_circuit_setup_e2e_rend_circ(or_circ,
- ntor_key_seed, sizeof(ntor_key_seed),
- 0);
+ retval = hs_circuit_setup_e2e_rend_circ(or_circ, ntor_key_seed,
+ sizeof(ntor_key_seed), 0);
tt_int_op(retval, OP_EQ, 0);
/**********************************************/
@@ -313,12 +353,12 @@ test_e2e_rend_circuit_setup(void *arg)
tt_int_op(retval, OP_EQ, 1);
/* Check that the crypt path has prop224 algorithm parameters */
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.f_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest),
OP_EQ, DIGEST_SHA3_256);
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.b_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest),
OP_EQ, DIGEST_SHA3_256);
- tt_assert(or_circ->cpath->crypto.f_crypto);
- tt_assert(or_circ->cpath->crypto.b_crypto);
+ tt_assert(or_circ->cpath->pvt_crypto.f_crypto);
+ tt_assert(or_circ->cpath->pvt_crypto.b_crypto);
/* Ensure that circ purpose was changed */
tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
@@ -389,15 +429,17 @@ test_client_pick_intro(void *arg)
tt_assert(encoded);
/* store it */
- hs_cache_store_as_client(encoded, &service_kp.pubkey);
+ ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
/* fetch it to make sure it works */
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(!tor_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);
}
@@ -405,6 +447,9 @@ test_client_pick_intro(void *arg)
/* 2) Mark all intro points except _the chosen one_ as failed. Then query the
* desc and get a random intro: check that we got _the chosen one_. */
{
+ /* Tell hs_get_extend_info_from_lspecs() to skip the private address check.
+ */
+ get_options_mutable()->ExtendAllowPrivateAddresses = 1;
/* Pick the chosen intro point and get its ei */
hs_desc_intro_point_t *chosen_intro_point =
smartlist_get(desc->encrypted_data.intro_points, 0);
@@ -432,7 +477,7 @@ test_client_pick_intro(void *arg)
for (int i = 0; i < 64; ++i) {
extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
tor_assert(ip);
- tt_assert(!tor_mem_is_zero((char*)ip->identity_digest, DIGEST_LEN));
+ tt_assert(!fast_mem_is_zero((char*)ip->identity_digest, DIGEST_LEN));
tt_mem_op(ip->identity_digest, OP_EQ, chosen_intro_ei->identity_digest,
DIGEST_LEN);
extend_info_free(ip);
@@ -478,12 +523,25 @@ test_client_pick_intro(void *arg)
SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
hs_desc_intro_point_t *, ip) {
extend_info_t *intro_ei = desc_intro_point_to_extend_info(ip);
+ /* desc_intro_point_to_extend_info() doesn't return IPv6 intro points
+ * yet, because we can't extend to them. See #24404, #24451, and #24181.
+ */
+ if (intro_ei == NULL) {
+ /* Pretend we're making a direct connection, and that we can use IPv6
+ */
+ get_options_mutable()->ClientUseIPv6 = 1;
+ intro_ei = hs_get_extend_info_from_lspecs(ip->link_specifiers,
+ &ip->onion_key, 1);
+ tt_assert(tor_addr_family(&intro_ei->orports[0].addr) == AF_INET6);
+ }
+ tt_assert(intro_ei);
if (intro_ei) {
const char *ptr;
char ip_addr[TOR_ADDR_BUF_LEN];
/* We need to decorate in case it is an IPv6 else routerset_parse()
* doesn't like it. */
- ptr = tor_addr_to_str(ip_addr, &intro_ei->addr, sizeof(ip_addr), 1);
+ ptr = tor_addr_to_str(ip_addr, &intro_ei->orports[0].addr,
+ sizeof(ip_addr), 1);
tt_assert(ptr == ip_addr);
ret = routerset_parse(get_options_mutable()->ExcludeNodes,
ip_addr, "");
@@ -531,6 +589,17 @@ mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
}
static void
+mock_connection_mark_unattached_ap_no_close(entry_connection_t *conn,
+ int endreason, int line,
+ const char *file)
+{
+ (void) conn;
+ (void) endreason;
+ (void) line;
+ (void) file;
+}
+
+static void
test_descriptor_fetch(void *arg)
{
int ret;
@@ -668,6 +737,10 @@ test_parse_auth_file_content(void *arg)
/* Bigger key than it should be */
tt_assert(!parse_auth_file_content("xx:descriptor:x25519:"
"vjqea4jbhwwc4hto7ekyvqfbeodghbaq6nxi45hz4wr3qvhqv3yqa"));
+ /* All-zeroes key */
+ tt_assert(!parse_auth_file_content("xx:descriptor:x25519:"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+
done:
tor_free(auth);
}
@@ -805,6 +878,7 @@ test_desc_has_arrived_cleanup(void *arg)
ed25519_keypair_t signing_kp;
entry_connection_t *socks1 = NULL, *socks2 = NULL;
hs_ident_dir_conn_t hs_dir_ident;
+ dir_connection_t *dir_conn = NULL;
(void) arg;
@@ -833,7 +907,7 @@ test_desc_has_arrived_cleanup(void *arg)
/* Store in the client cache. */
ret = hs_cache_store_as_client(desc_str, &signing_kp.pubkey);
- tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey);
tt_assert(cached_desc);
hs_helper_desc_equal(desc, cached_desc);
@@ -861,9 +935,11 @@ test_desc_has_arrived_cleanup(void *arg)
* SOCKS connection to be ended with a resolved failed. */
hs_ident_dir_conn_init(&signing_kp.pubkey,
&desc->plaintext_data.blinded_pubkey, &hs_dir_ident);
- hs_client_desc_has_arrived(&hs_dir_ident);
+ dir_conn = dir_connection_new(AF_INET);
+ dir_conn->hs_ident = hs_ident_dir_conn_dup(&hs_dir_ident);
+ hs_client_dir_fetch_done(dir_conn, "A reason", desc_str, 200);
+ connection_free_minimal(TO_CONN(dir_conn));
tt_int_op(socks1->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED);
- /* XXX: MUST work with OP_EQ. */
tt_int_op(socks2->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED);
/* Now let say tor cleans up the intro state cache which resets all intro
@@ -872,7 +948,6 @@ test_desc_has_arrived_cleanup(void *arg)
/* Retrying all SOCKS which should basically do nothing since we don't have
* any pending SOCKS connection in AP_CONN_STATE_RENDDESC_WAIT state. */
- /* XXX: BUG() is triggered here, shouldn't if socks2 wasn't alive. */
retry_all_socks_conn_waiting_for_desc();
done:
@@ -899,6 +974,7 @@ test_close_intro_circuits_new_desc(void *arg)
(void) arg;
hs_init();
+ rend_cache_init();
/* This is needed because of the client cache expiration timestamp is based
* on having a consensus. See cached_client_descriptor_has_expired(). */
@@ -923,6 +999,51 @@ test_close_intro_circuits_new_desc(void *arg)
circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
ocirc = TO_ORIGIN_CIRCUIT(circ);
+ /* Build a descriptor _without_ client authorization and thus not
+ * decryptable. Make sure the close circuit code path is not triggered. */
+ {
+ char *desc_encoded = NULL;
+ uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
+ curve25519_keypair_t client_kp;
+ hs_descriptor_t *desc = NULL;
+
+ tt_int_op(0, OP_EQ, curve25519_keypair_generate(&client_kp, 0));
+ crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
+
+ desc = hs_helper_build_hs_desc_with_client_auth(descriptor_cookie,
+ &client_kp.pubkey,
+ &service_kp);
+ tt_assert(desc);
+ ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
+ &desc_encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Associate descriptor intro key with the dummy circuit. */
+ const hs_desc_intro_point_t *ip =
+ smartlist_get(desc->encrypted_data.intro_points, 0);
+ tt_assert(ip);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk,
+ &ip->auth_key_cert->signed_key);
+ hs_descriptor_free(desc);
+ tt_assert(desc_encoded);
+ /* Put it in the cache. Should not be decrypted since the client
+ * authorization creds were not added to the global map. */
+ ret = hs_cache_store_as_client(desc_encoded, &service_kp.pubkey);
+ tor_free(desc_encoded);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
+
+ /* Clean cache with a future timestamp. It will trigger the clean up and
+ * attempt to close the circuit but only if the descriptor is decryptable.
+ * Cache object should be removed and circuit untouched. */
+ hs_cache_clean_as_client(mock_ns.valid_after + (60 * 60 * 24));
+ tt_assert(!hs_cache_lookup_as_client(&service_kp.pubkey));
+
+ /* Make sure the circuit still there. */
+ tt_assert(circuit_get_next_intro_circ(NULL, true));
+ /* Get rid of the ident, it will be replaced in the next tests. */
+ hs_ident_circuit_free(ocirc->hs_ident);
+ }
+
/* Build the first descriptor and cache it. */
{
char *encoded;
@@ -934,7 +1055,7 @@ test_close_intro_circuits_new_desc(void *arg)
/* Store it */
ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
- tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tor_free(encoded);
tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
}
@@ -944,8 +1065,7 @@ test_close_intro_circuits_new_desc(void *arg)
const hs_desc_intro_point_t *ip =
smartlist_get(desc1->encrypted_data.intro_points, 0);
tt_assert(ip);
- ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey,
- HS_IDENT_CIRCUIT_INTRO);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk,
&ip->auth_key_cert->signed_key);
}
@@ -971,7 +1091,7 @@ test_close_intro_circuits_new_desc(void *arg)
tt_assert(encoded);
ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
- tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tor_free(encoded);
tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
}
@@ -988,6 +1108,451 @@ test_close_intro_circuits_new_desc(void *arg)
UNMOCK(networkstatus_get_reasonably_live_consensus);
}
+static void
+test_close_intro_circuits_cache_clean(void *arg)
+{
+ int ret;
+ ed25519_keypair_t service_kp;
+ circuit_t *circ = NULL;
+ origin_circuit_t *ocirc = NULL;
+ hs_descriptor_t *desc1 = NULL;
+
+ (void) arg;
+
+ hs_init();
+ rend_cache_init();
+
+ /* This is needed because of the client cache expiration timestamp is based
+ * on having a consensus. See cached_client_descriptor_has_expired(). */
+ MOCK(networkstatus_get_reasonably_live_consensus,
+ mock_networkstatus_get_reasonably_live_consensus);
+
+ /* Set consensus time */
+ parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
+ &mock_ns.valid_until);
+
+ /* Generate service keypair */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
+
+ /* Create and add to the global list a dummy client introduction circuits.
+ * We'll then make sure the hs_ident is attached to a dummy descriptor. */
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+
+ /* Build the first descriptor and cache it. */
+ {
+ char *encoded;
+ desc1 = hs_helper_build_hs_desc_with_ip(&service_kp);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(encoded);
+
+ /* Store it */
+ ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, 0);
+ tor_free(encoded);
+ tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
+ }
+
+ /* We'll pick one introduction point and associate it with the circuit. */
+ {
+ const hs_desc_intro_point_t *ip =
+ smartlist_get(desc1->encrypted_data.intro_points, 0);
+ tt_assert(ip);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk,
+ &ip->auth_key_cert->signed_key);
+ }
+
+ /* Before we are about to clean up the intro circuits, make sure it is
+ * actually there. */
+ tt_assert(circuit_get_next_intro_circ(NULL, true));
+
+ /* Cleanup the client cache. The ns valid after time is what decides if the
+ * descriptor has expired so put it in the future enough (72h) so we are
+ * sure to always expire. */
+ mock_ns.valid_after = approx_time() + (72 * 24 * 60 * 60);
+ hs_cache_clean_as_client(0);
+
+ /* Once stored, our intro circuit should be closed because it is related to
+ * an old introduction point that doesn't exists anymore. */
+ tt_assert(!circuit_get_next_intro_circ(NULL, true));
+
+ done:
+ circuit_free(circ);
+ hs_descriptor_free(desc1);
+ hs_free_all();
+ rend_cache_free_all();
+ UNMOCK(networkstatus_get_reasonably_live_consensus);
+}
+
+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;
+ dir_connection_t *dir_conn = NULL;
+ hs_descriptor_t *desc = NULL;
+ uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
+
+ (void) arg;
+
+ MOCK(networkstatus_get_reasonably_live_consensus,
+ mock_networkstatus_get_reasonably_live_consensus);
+ MOCK(connection_mark_unattached_ap_,
+ mock_connection_mark_unattached_ap_no_close);
+ MOCK(read_file_to_str, mock_read_file_to_str);
+ MOCK(tor_listdir, mock_tor_listdir);
+ MOCK(check_private_dir, mock_check_private_dir);
+
+ /* Set consensus time */
+ parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
+ &mock_ns.valid_until);
+
+ hs_init();
+
+ ret = ed25519_keypair_generate(&service_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = ed25519_keypair_generate(&signing_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+
+ socks_conn = helper_build_socks_connection(&service_kp.pubkey,
+ AP_CONN_STATE_RENDDESC_WAIT);
+ tt_assert(socks_conn);
+
+ /* Create directory connection. */
+ dir_conn = dir_connection_new(AF_INET);
+ dir_conn->hs_ident = tor_malloc_zero(sizeof(hs_ident_dir_conn_t));
+ TO_CONN(dir_conn)->purpose = DIR_PURPOSE_FETCH_HSDESC;
+ ed25519_pubkey_copy(&dir_conn->hs_ident->identity_pk, &service_kp.pubkey);
+
+ /* Encode descriptor so we can decode it. */
+ 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);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(desc_encoded);
+
+ /* Try decoding. Point this to an existing descriptor. The following should
+ * fail thus the desc_out should be set to NULL. */
+ hs_descriptor_t *desc_out = desc;
+ ret = hs_client_decode_descriptor(desc_encoded, &service_kp.pubkey,
+ &desc_out);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
+ tt_assert(desc_out == NULL);
+
+ /* The caching will fail to decrypt because the descriptor_cookie used above
+ * is not known to the HS subsystem. This will lead to a missing client
+ * auth. */
+ 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_MISSING_CLIENT_AUTH);
+
+ /* Add in the global client auth list bad creds for this service. */
+ helper_add_random_client_auth(&service_kp.pubkey);
+
+ ret = hs_client_decode_descriptor(desc_encoded, &service_kp.pubkey,
+ &desc_out);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_BAD_CLIENT_AUTH);
+ tt_assert(desc_out == NULL);
+
+ /* Simmulate a fetch done again. This should replace the cached descriptor
+ * and signal a bad client authorization. */
+ 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_BAD_CLIENT_AUTH);
+
+ done:
+ connection_free_minimal(ENTRY_TO_CONN(socks_conn));
+ connection_free_minimal(TO_CONN(dir_conn));
+ hs_descriptor_free(desc);
+ tor_free(desc_encoded);
+ circuit_free(circ);
+
+ hs_free_all();
+
+ UNMOCK(networkstatus_get_reasonably_live_consensus);
+ UNMOCK(connection_mark_unattached_ap_);
+ UNMOCK(read_file_to_str);
+ UNMOCK(tor_listdir);
+ UNMOCK(check_private_dir);
+}
+
+static void
+test_close_intro_circuit_failure(void *arg)
+{
+ char digest[DIGEST_LEN];
+ circuit_t *circ = NULL;
+ ed25519_keypair_t service_kp, intro_kp;
+ origin_circuit_t *ocirc = NULL;
+ tor_addr_t addr;
+ const hs_cache_intro_state_t *entry;
+
+ (void) arg;
+
+ hs_init();
+
+ /* Generate service keypair */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&intro_kp, 0));
+
+ /* Create and add to the global list a dummy client introduction circuit at
+ * the ACK WAIT state. */
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
+ 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);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
+
+ /* We'll make for close the circuit for a timeout failure. It should _NOT_
+ * end up in the failure cache just yet. We do that on free() only. */
+ circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
+ tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
+ &intro_kp.pubkey));
+ /* Time to free. It should get removed. */
+ circuit_free(circ);
+ entry = hs_cache_client_intro_state_find(&service_kp.pubkey,
+ &intro_kp.pubkey);
+ tt_assert(entry);
+ tt_uint_op(entry->timed_out, OP_EQ, 1);
+ hs_cache_client_intro_state_purge();
+
+ /* Again, create and add to the global list a dummy client introduction
+ * circuit at the INTRODUCING state. */
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+ 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);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
+
+ /* On free, we should get an unreachable failure. */
+ circuit_free(circ);
+ entry = hs_cache_client_intro_state_find(&service_kp.pubkey,
+ &intro_kp.pubkey);
+ tt_assert(entry);
+ tt_uint_op(entry->unreachable_count, OP_EQ, 1);
+ hs_cache_client_intro_state_purge();
+
+ /* Again, create and add to the global list a dummy client introduction
+ * circuit at the INTRODUCING state but we'll close it for timeout. It
+ * should not be noted as a timeout failure. */
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+ 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);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
+
+ circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
+ circuit_free(circ);
+ tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
+ &intro_kp.pubkey));
+
+ /* Again, create and add to the global list a dummy client introduction
+ * circuit at the INTRODUCING state but without a chosen_exit. In theory, it
+ * can not happen but we'll make sure it doesn't end up in the failure cache
+ * anyway. */
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
+
+ circuit_free(circ);
+ tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
+ &intro_kp.pubkey));
+
+ done:
+ circuit_free(circ);
+ hs_free_all();
+}
+
+static void
+test_purge_ephemeral_client_auth(void *arg)
+{
+ ed25519_keypair_t service_kp;
+ hs_client_service_authorization_t *auth = NULL;
+ hs_client_register_auth_status_t status;
+
+ (void) arg;
+
+ /* We will try to write on disk client credentials. */
+ MOCK(check_private_dir, mock_check_private_dir);
+ MOCK(get_options, mock_get_options);
+ MOCK(write_str_to_file, mock_write_str_to_file);
+
+ /* Bogus directory so when we try to write the permanent client
+ * authorization data to disk, we don't fail. See
+ * store_permanent_client_auth_credentials() for more details. */
+ mocked_options.ClientOnionAuthDir = tor_strdup("auth_dir");
+
+ hs_init();
+
+ /* Generate service keypair */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
+
+ /* Generate a client authorization object. */
+ auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t));
+
+ /* Set it up. No flags meaning it is ephemeral. */
+ curve25519_secret_key_generate(&auth->enc_seckey, 0);
+ hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address);
+ auth->flags = 0;
+
+ /* Confirm that there is nothing in the client auth map. It is unallocated
+ * until we add the first entry. */
+ tt_assert(!get_hs_client_auths_map());
+
+ /* Add an entry to the client auth list. We loose ownership of the auth
+ * object so nullify it. */
+ status = hs_client_register_auth_credentials(auth);
+ auth = NULL;
+ tt_int_op(status, OP_EQ, REGISTER_SUCCESS);
+
+ /* We should have the entry now. */
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ tt_assert(client_auths);
+ tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
+
+ /* Purge the cache that should remove all ephemeral values. */
+ purge_ephemeral_client_auth();
+ tt_int_op(digest256map_size(client_auths), OP_EQ, 0);
+
+ /* Now add a new authorization object but permanent. */
+ /* Generate a client authorization object. */
+ auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t));
+ curve25519_secret_key_generate(&auth->enc_seckey, 0);
+ hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address);
+ auth->flags = CLIENT_AUTH_FLAG_IS_PERMANENT;
+
+ /* Add an entry to the client auth list. We loose ownership of the auth
+ * object so nullify it. */
+ status = hs_client_register_auth_credentials(auth);
+ auth = NULL;
+ tt_int_op(status, OP_EQ, REGISTER_SUCCESS);
+ tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
+
+ /* Purge again, the entry should still be there. */
+ purge_ephemeral_client_auth();
+ tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
+
+ done:
+ client_service_authorization_free(auth);
+ hs_free_all();
+ tor_free(mocked_options.ClientOnionAuthDir);
+
+ UNMOCK(check_private_dir);
+ UNMOCK(get_options);
+ UNMOCK(write_str_to_file);
+}
+
struct testcase_t hs_client_tests[] = {
{ "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy,
TT_FORK, NULL, NULL },
@@ -1005,8 +1570,19 @@ struct testcase_t hs_client_tests[] = {
TT_FORK, NULL, NULL },
{ "desc_has_arrived_cleanup", test_desc_has_arrived_cleanup,
TT_FORK, NULL, NULL },
+ { "close_intro_circuit_failure", test_close_intro_circuit_failure,
+ TT_FORK, NULL, NULL },
{ "close_intro_circuits_new_desc", test_close_intro_circuits_new_desc,
TT_FORK, NULL, NULL },
+ { "close_intro_circuits_cache_clean", test_close_intro_circuits_cache_clean,
+ TT_FORK, NULL, NULL },
+
+ /* SOCKS5 Extended Error Code. */
+ { "socks_hs_errors", test_socks_hs_errors, TT_FORK, NULL, NULL },
+
+ /* Client authorization. */
+ { "purge_ephemeral_client_auth", test_purge_ephemeral_client_auth, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
index a763b62356..fccf638a07 100644
--- a/src/test/test_hs_common.c
+++ b/src/test/test_hs_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,6 +6,7 @@
* \brief Test hidden service common functionalities.
*/
+#define CONNECTION_EDGE_PRIVATE
#define HS_COMMON_PRIVATE
#define HS_CLIENT_PRIVATE
#define HS_SERVICE_PRIVATE
@@ -31,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"
@@ -52,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) */
@@ -82,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. */
@@ -275,7 +276,7 @@ test_start_time_of_next_time_period(void *arg)
static void
cleanup_nodelist(void)
{
- smartlist_t *nodelist = nodelist_get_list();
+ const smartlist_t *nodelist = nodelist_get_list();
SMARTLIST_FOREACH_BEGIN(nodelist, node_t *, node) {
tor_free(node->md);
node->md = NULL;
@@ -292,7 +293,6 @@ helper_add_hsdir_to_networkstatus(networkstatus_t *ns,
routerstatus_t *rs = tor_malloc_zero(sizeof(routerstatus_t));
routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t));
uint8_t identity[DIGEST_LEN];
- tor_addr_t ipv4_addr;
node_t *node = NULL;
memset(identity, identity_idx, sizeof(identity));
@@ -301,9 +301,8 @@ helper_add_hsdir_to_networkstatus(networkstatus_t *ns,
rs->is_hs_dir = is_hsdir;
rs->pv.supports_v3_hsdir = 1;
strlcpy(rs->nickname, nickname, sizeof(rs->nickname));
- tor_addr_parse(&ipv4_addr, "1.2.3.4");
- ri->addr = tor_addr_to_ipv4h(&ipv4_addr);
- rs->addr = tor_addr_to_ipv4h(&ipv4_addr);
+ tor_addr_parse(&ri->ipv4_addr, "1.2.3.4");
+ tor_addr_parse(&rs->ipv4_addr, "1.2.3.4");
ri->nickname = tor_strdup(nickname);
ri->protocol_list = tor_strdup("HSDir=1-2 LinkAuth=3");
memcpy(ri->cache_info.identity_digest, identity, DIGEST_LEN);
@@ -490,7 +489,7 @@ test_desc_reupload_logic(void *arg)
* 1) Upload descriptor to HSDirs
* CHECK that previous_hsdirs list was populated.
* 2) Then call router_dir_info_changed() without an HSDir set change.
- * CHECK that no reuplod occurs.
+ * CHECK that no reupload occurs.
* 3) Now change the HSDir set, and call dir_info_changed() again.
* CHECK that reupload occurs.
* 4) Finally call service_desc_schedule_upload().
@@ -509,6 +508,7 @@ test_desc_reupload_logic(void *arg)
pubkey_hex, strlen(pubkey_hex));
hs_build_address(&pubkey, HS_VERSION_THREE, onion_addr);
service = tor_malloc_zero(sizeof(hs_service_t));
+ tt_assert(service);
memcpy(service->onion_address, onion_addr, sizeof(service->onion_address));
ed25519_secret_key_generate(&service->keys.identity_sk, 0);
ed25519_public_key_generate(&service->keys.identity_pk,
@@ -610,6 +610,10 @@ test_desc_reupload_logic(void *arg)
SMARTLIST_FOREACH(ns->routerstatus_list,
routerstatus_t *, rs, routerstatus_free(rs));
smartlist_clear(ns->routerstatus_list);
+ if (service) {
+ remove_service(get_hs_service_map(), service);
+ hs_service_free(service);
+ }
networkstatus_vote_free(ns);
cleanup_nodelist();
hs_free_all();
@@ -637,7 +641,7 @@ test_disaster_srv(void *arg)
get_disaster_srv(1, srv_one);
get_disaster_srv(2, srv_two);
- /* Check that the cached ones where updated */
+ /* Check that the cached ones were updated */
tt_mem_op(cached_disaster_srv_one, OP_EQ, srv_one, DIGEST256_LEN);
tt_mem_op(cached_disaster_srv_two, OP_EQ, srv_two, DIGEST256_LEN);
@@ -780,6 +784,7 @@ static void
test_parse_extended_hostname(void *arg)
{
(void) arg;
+ hostname_type_t type;
char address1[] = "fooaddress.onion";
char address2[] = "aaaaaaaaaaaaaaaa.onion";
@@ -790,18 +795,45 @@ test_parse_extended_hostname(void *arg)
char address7[] = ".abcdefghijklmnop.onion";
char address8[] =
"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);
+
+ tt_assert(!parse_extended_hostname(address2, &type));
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
+
+ tt_assert(parse_extended_hostname(address3, &type));
+ tt_int_op(type, OP_EQ, EXIT_HOSTNAME);
+
+ tt_assert(parse_extended_hostname(address4, &type));
+ tt_int_op(type, OP_EQ, NORMAL_HOSTNAME);
- tt_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
- tt_assert(BAD_HOSTNAME == parse_extended_hostname(address2));
- tt_assert(EXIT_HOSTNAME == parse_extended_hostname(address3));
- tt_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4));
- tt_assert(BAD_HOSTNAME == parse_extended_hostname(address5));
- tt_assert(BAD_HOSTNAME == parse_extended_hostname(address6));
- tt_assert(BAD_HOSTNAME == parse_extended_hostname(address7));
- tt_assert(ONION_V3_HOSTNAME == parse_extended_hostname(address8));
+ tt_assert(!parse_extended_hostname(address5, &type));
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
+
+ tt_assert(!parse_extended_hostname(address6, &type));
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
+
+ tt_assert(!parse_extended_hostname(address7, &type));
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
+
+ tt_assert(parse_extended_hostname(address8, &type));
+ tt_int_op(type, OP_EQ, ONION_V3_HOSTNAME);
tt_str_op(address8, OP_EQ,
"25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid");
+ /* Invalid v3 address. */
+ tt_assert(!parse_extended_hostname(address9, &type));
+ 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: ;
}
@@ -829,7 +861,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);
@@ -837,7 +869,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);
@@ -845,7 +877,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);
@@ -853,7 +885,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);
@@ -861,7 +893,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);
@@ -1351,7 +1383,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,
@@ -1364,7 +1396,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,
@@ -1587,7 +1619,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 bd9c1b03ae..20e6b014ee 100644
--- a/src/test/test_hs_config.c
+++ b/src/test/test_hs_config.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,6 +12,7 @@
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
+#include "test/resolve_test_helpers.h"
#include "app/config/config.h"
#include "feature/hs/hs_common.h"
@@ -73,8 +74,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();
}
@@ -87,8 +89,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();
}
@@ -101,8 +104,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();
}
@@ -263,6 +267,7 @@ test_valid_service_v3(void *arg)
int ret;
(void) arg;
+ mock_hostname_resolver();
/* Valid complex configuration. */
{
@@ -303,7 +308,7 @@ test_valid_service_v3(void *arg)
}
done:
- ;
+ unmock_hostname_resolver();
}
static void
@@ -344,6 +349,114 @@ test_staging_service_v3(void *arg)
hs_free_all();
}
+static void
+test_dos_parameters(void *arg)
+{
+ int ret;
+
+ (void) arg;
+
+ hs_init();
+
+ /* Valid configuration. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 22 1.1.1.1:22\n"
+ "HiddenServiceEnableIntroDoSDefense 1\n"
+ "HiddenServiceEnableIntroDoSRatePerSec 42\n"
+ "HiddenServiceEnableIntroDoSBurstPerSec 87\n";
+
+ setup_full_capture_of_logs(LOG_INFO);
+ ret = helper_config_service(conf, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ expect_log_msg_containing("Service INTRO2 DoS defenses rate set to: 42");
+ expect_log_msg_containing("Service INTRO2 DoS defenses burst set to: 87");
+ teardown_capture_of_logs();
+ }
+
+ /* Invalid rate. Value of 2^37. Max allowed is 2^31. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 22 1.1.1.1:22\n"
+ "HiddenServiceEnableIntroDoSDefense 1\n"
+ "HiddenServiceEnableIntroDoSRatePerSec 137438953472\n"
+ "HiddenServiceEnableIntroDoSBurstPerSec 87\n";
+
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 0);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceEnableIntroDoSRatePerSec: "
+ "Integer 137438953472 is malformed or out of "
+ "bounds.");
+ teardown_capture_of_logs();
+ }
+
+ /* Invalid burst. Value of 2^38. Max allowed is 2^31. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 22 1.1.1.1:22\n"
+ "HiddenServiceEnableIntroDoSDefense 1\n"
+ "HiddenServiceEnableIntroDoSRatePerSec 42\n"
+ "HiddenServiceEnableIntroDoSBurstPerSec 274877906944\n";
+
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 0);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceEnableIntroDoSBurstPerSec: "
+ "Integer 274877906944 is malformed or out "
+ "of bounds.");
+ teardown_capture_of_logs();
+ }
+
+ /* Burst is smaller than rate. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 22 1.1.1.1:22\n"
+ "HiddenServiceEnableIntroDoSDefense 1\n"
+ "HiddenServiceEnableIntroDoSRatePerSec 42\n"
+ "HiddenServiceEnableIntroDoSBurstPerSec 27\n";
+
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 0);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Hidden service DoS defenses burst (27) can "
+ "not be smaller than the rate value (42).");
+ teardown_capture_of_logs();
+ }
+
+ /* Negative value. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 22 1.1.1.1:22\n"
+ "HiddenServiceEnableIntroDoSDefense 1\n"
+ "HiddenServiceEnableIntroDoSRatePerSec -1\n"
+ "HiddenServiceEnableIntroDoSBurstPerSec 42\n";
+
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 0);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceEnableIntroDoSRatePerSec: "
+ "Integer -1 is malformed or out of bounds.");
+ teardown_capture_of_logs();
+ }
+
+ done:
+ hs_free_all();
+}
+
struct testcase_t hs_config_tests[] = {
/* Invalid service not specific to any version. */
{ "invalid_service", test_invalid_service, TT_FORK,
@@ -361,6 +474,9 @@ struct testcase_t hs_config_tests[] = {
{ "staging_service_v3", test_staging_service_v3, TT_FORK,
NULL, NULL },
+ /* Test HS DoS parameters. */
+ { "dos_parameters", test_dos_parameters, TT_FORK,
+ NULL, NULL },
+
END_OF_TESTCASES
};
-
diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c
index ba67712f1b..6e41c4994f 100644
--- a/src/test/test_hs_control.c
+++ b/src/test/test_hs_control.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,13 +6,21 @@
* \brief Unit tests for hidden service control port event and command.
**/
-#define CONTROL_PRIVATE
+#define CONTROL_EVENTS_PRIVATE
+#define HS_CLIENT_PRIVATE
#include "core/or/or.h"
#include "test/test.h"
+#include "test/test_helpers.h"
+#include "core/mainloop/connection.h"
#include "feature/control/control.h"
+#include "feature/control/control_events.h"
+#include "feature/control/control_cmd.h"
+#include "feature/control/control_fmt.h"
+#include "feature/control/control_connection_st.h"
#include "app/config/config.h"
#include "feature/hs/hs_common.h"
+#include "feature/hs/hs_client.h"
#include "feature/hs/hs_control.h"
#include "feature/nodelist/nodelist.h"
@@ -20,7 +28,16 @@
#include "feature/nodelist/routerstatus_st.h"
#include "lib/crypt_ops/crypto_format.h"
-#include "test/test_helpers.h"
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef _WIN32
+/* For mkdir() */
+#include <direct.h>
+#else
+#include <dirent.h>
+#endif /* defined(_WIN32) */
/* mock ID digest and longname for node that's in nodelist */
#define HSDIR_EXIST_ID \
@@ -105,8 +122,7 @@ test_hs_desc_event(void *arg)
memset(&blinded_pk, 'B', sizeof(blinded_pk));
memset(&hsdir_rs, 0, sizeof(hsdir_rs));
memcpy(hsdir_rs.identity_digest, HSDIR_EXIST_ID, DIGEST_LEN);
- ret = ed25519_public_to_base64(base64_blinded_pk, &blinded_pk);
- tt_int_op(ret, OP_EQ, 0);
+ ed25519_public_to_base64(base64_blinded_pk, &blinded_pk);
memcpy(&ident.identity_pk, &identity_kp.pubkey,
sizeof(ed25519_public_key_t));
memcpy(&ident.blinded_pk, &blinded_pk, sizeof(blinded_pk));
@@ -186,9 +202,552 @@ test_hs_desc_event(void *arg)
tor_free(expected_msg);
}
+/** Test that we can correctly add, remove and view client auth credentials
+ * using the control port. */
+static void
+test_hs_control_good_onion_client_auth_add(void *arg)
+{
+ (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,
+ service_identity_pk_jam;
+ control_connection_t conn;
+ char *args = NULL;
+ char *cp1 = NULL;
+ size_t sz;
+
+ hs_init();
+
+ { /* Setup the control conn */
+ memset(&conn, 0, sizeof(control_connection_t));
+ TO_CONN(&conn)->outbuf = buf_new();
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD");
+ }
+
+ { /* Setup the services */
+ retval = hs_parse_address(
+ "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd",
+ &service_identity_pk_2fv,
+ NULL, NULL);
+ tt_int_op(retval, OP_EQ, 0);
+
+ retval = hs_parse_address(
+ "jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd",
+ &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();
+ tt_assert(!client_auths);
+
+ /* Register first service */
+ args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
+ "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= ");
+
+ 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);
+ tor_free(args);
+
+ /* Register second service (even with an unrecognized argument) */
+ args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
+ "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA= DropSound=No");
+
+ 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);
+ 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, 3);
+
+ hs_client_service_authorization_t *client_2fv =
+ digest256map_get(client_auths, service_identity_pk_2fv.pubkey);
+ tt_assert(client_2fv);
+ tt_int_op(client_2fv->flags, OP_EQ, 0);
+
+ hs_client_service_authorization_t *client_jt4 =
+ digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
+ 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");
+
+ /* First go with no arguments, so that we view all the credentials */
+ tor_free(args);
+ args = tor_strdup("");
+
+#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"
+
+ 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, VIEW_CORRECT_REPLY_NO_ADDR);
+ tor_free(cp1);
+
+ /* Now specify an HS addr, and see that we only view those creds */
+ tor_free(args);
+ args =
+ tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd");
+
+#define VIEW_CORRECT_REPLY_JT4 "250-ONION_CLIENT_AUTH_VIEW " \
+ "jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd\r\n" \
+ "250-CLIENT jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " \
+ "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=\r\n" \
+ "250 OK\r\n"
+
+ 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, VIEW_CORRECT_REPLY_JT4);
+ tor_free(cp1);
+
+ /* Now try to REMOVE the auth credentials */
+ tor_free(conn.current_cmd);
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_REMOVE");
+
+ /* First try with a wrong addr */
+ tor_free(args);
+ args = tor_strdup("thatsok");
+
+ 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 address \"thatsok\"\r\n");
+ tor_free(cp1);
+
+ client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
+ tt_assert(client_jt4);
+
+ /* Now actually remove them. */
+ tor_free(args);
+ args =tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd");
+
+ 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);
+
+ client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
+ tt_assert(!client_jt4);
+
+ /* Now try another time (we should get 'already removed' msg) */
+ 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, "251 No credentials for "
+ "\"jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd\"\r\n");
+ tor_free(cp1);
+
+ client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
+ tt_assert(!client_jt4);
+
+ /* Now also remove the other one */
+ tor_free(args);
+ 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);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "250 OK\r\n");
+ tor_free(cp1);
+
+ /* Finally, do another VIEW and see that we get nothing. */
+ tor_free(conn.current_cmd);
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_VIEW");
+ tor_free(args);
+ args = tor_strdup("");
+
+#define VIEW_CORRECT_REPLY_NOTHING "250-ONION_CLIENT_AUTH_VIEW\r\n250 OK\r\n"
+
+ 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, VIEW_CORRECT_REPLY_NOTHING);
+ tor_free(cp1);
+
+ /* And a final VIEW with a wrong HS addr */
+ tor_free(args);
+ args = tor_strdup("house");
+
+ 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 address \"house\"\r\n");
+
+ done:
+ tor_free(args);
+ tor_free(cp1);
+ buf_free(TO_CONN(&conn)->outbuf);
+ tor_free(conn.current_cmd);
+ hs_client_free_all();
+}
+
+/** Test some error cases of ONION_CLIENT_AUTH_ADD */
+static void
+test_hs_control_bad_onion_client_auth_add(void *arg)
+{
+ (void) arg;
+
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+
+ int retval;
+ control_connection_t conn;
+ char *cp1 = NULL;
+ size_t sz;
+ char *args = NULL;
+
+ hs_init();
+
+ { /* Setup the control conn */
+ memset(&conn, 0, sizeof(control_connection_t));
+ TO_CONN(&conn)->outbuf = buf_new();
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD");
+ }
+
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ tt_assert(!client_auths);
+
+ /* Register first service */
+ args = tor_strdup(
+ "badaddr x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ=");
+
+ 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, "512 Invalid v3 address \"badaddr\"\r\n");
+
+ tor_free(cp1);
+ tor_free(args);
+
+ /* Register second service (even with an unrecognized argument) */
+ args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
+ "love:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=");
+
+ 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, "552 Unrecognized key type \"love\"\r\n");
+
+ tor_free(cp1);
+ tor_free(args);
+
+ /* Register second service (even with an unrecognized argument) */
+ args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
+ "x25519:QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEK");
+
+ 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, "512 Failed to decode x25519 private key\r\n");
+
+ tor_free(cp1);
+ tor_free(args);
+
+ /* Register with an all zero client key */
+ args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
+ "x25519:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
+ 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, "553 Invalid private key \"AAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAAAAAAAA=\"\r\n");
+
+ client_auths = get_hs_client_auths_map();
+ tt_assert(!client_auths);
+
+ done:
+ tor_free(args);
+ tor_free(cp1);
+ buf_free(TO_CONN(&conn)->outbuf);
+ tor_free(conn.current_cmd);
+ hs_client_free_all();
+}
+
+/** Test that we can correctly add permanent client auth credentials using the
+ * control port. */
+static void
+test_hs_control_store_permanent_creds(void *arg)
+{
+ (void) arg;
+
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+
+ int retval;
+ ed25519_public_key_t service_identity_pk_2fv;
+ control_connection_t conn;
+ char *args = NULL;
+ char *cp1 = NULL;
+ char *creds_file_str = NULL;
+ char *creds_fname = NULL;
+
+ size_t sz;
+
+ hs_init();
+
+ { /* Setup the control conn */
+ memset(&conn, 0, sizeof(control_connection_t));
+ TO_CONN(&conn)->outbuf = buf_new();
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD");
+ }
+
+ { /* Setup the services */
+ retval = hs_parse_address(
+ "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd",
+ &service_identity_pk_2fv,
+ NULL, NULL);
+ tt_int_op(retval, OP_EQ, 0);
+ }
+
+ digest256map_t *client_auths = get_hs_client_auths_map();
+ tt_assert(!client_auths);
+
+ /* Try registering first service with no ClientOnionAuthDir set */
+ args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
+ "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= "
+ "Flags=Permanent");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check control port response. This one should fail. */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "553 Unable to store creds for "
+ "\"2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd\"\r\n");
+
+ { /* Setup ClientOnionAuthDir */
+ int ret;
+ char *perm_creds_dir = tor_strdup(get_fname("permanent_credentials"));
+ get_options_mutable()->ClientOnionAuthDir = perm_creds_dir;
+
+ #ifdef _WIN32
+ ret = mkdir(perm_creds_dir);
+ #else
+ ret = mkdir(perm_creds_dir, 0700);
+ #endif
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ tor_free(args);
+ tor_free(cp1);
+
+ /* Try the control port command again. This time it should work! */
+ args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
+ "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= "
+ "Flags=Permanent");
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check control port response */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "250 OK\r\n");
+
+ /* Check file contents! */
+ creds_fname = tor_strdup(get_fname("permanent_credentials/"
+ "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd.auth_private"));
+ creds_file_str = read_file_to_str(creds_fname, RFTS_BIN, NULL);
+
+ tt_assert(creds_file_str);
+ tt_str_op(creds_file_str, OP_EQ,
+ "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd:descriptor:"
+ /* base32 representation of the base64 iJ1t... key above */
+ "x25519:rcow3dfavmyanyqvhwnvnmfdqw34ydtrgv7jnelmqs4wi4uuxrca");
+
+ tor_free(args);
+ tor_free(cp1);
+
+ /* Overwrite the credentials and check that they got overwrited. */
+ args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
+ "x25519:UDRvZLvcJo0QRLvDfkpgbtsqbkhIUQZyeo2FNBrgS18= "
+ "Flags=Permanent");
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check control port response: we replaced! */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "251 Client for onion existed and replaced\r\n");
+
+ tor_free(creds_file_str);
+
+ /* Check creds file contents again. See that the key got updated */
+ creds_file_str = read_file_to_str(creds_fname, RFTS_BIN, NULL);
+ tt_assert(creds_file_str);
+ tt_str_op(creds_file_str, OP_EQ,
+ "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd:descriptor:"
+ /* base32 representation of the base64 UDRv... key above */
+ "x25519:ka2g6zf33qti2ecexpbx4stan3nsu3sijbiqm4t2rwctigxajnpq");
+
+ /* Now for our next act!!! Actually get the HS client subsystem to parse the
+ * whole directory and make sure that it extracted the right credential! */
+ hs_config_client_authorization(get_options(), 0);
+
+ client_auths = get_hs_client_auths_map();
+ tt_assert(client_auths);
+ tt_uint_op(digest256map_size(client_auths), OP_EQ, 1);
+
+ hs_client_service_authorization_t *client_2fv =
+ digest256map_get(client_auths, service_identity_pk_2fv.pubkey);
+ tt_assert(client_2fv);
+ tt_int_op(client_2fv->flags, OP_EQ, CLIENT_AUTH_FLAG_IS_PERMANENT);
+ tt_str_op(hex_str((char*)client_2fv->enc_seckey.secret_key, 32), OP_EQ,
+ "50346F64BBDC268D1044BBC37E4A606EDB2A6E48485106727A8D85341AE04B5F");
+
+ /* And now for the final act! Use the REMOVE control port command to remove
+ the credential, and ensure that the file has also been removed! */
+ tor_free(conn.current_cmd);
+ tor_free(cp1);
+ tor_free(args);
+
+ /* Ensure that the creds file exists */
+ tt_int_op(file_status(creds_fname), OP_EQ, FN_FILE);
+
+ /* Do the REMOVE */
+ conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_REMOVE");
+ 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");
+
+ /* Ensure that the file has been removed and the map is empty */
+ tt_int_op(file_status(creds_fname), OP_EQ, FN_NOENT);
+ tt_uint_op(digest256map_size(client_auths), OP_EQ, 0);
+
+ done:
+ tor_free(get_options_mutable()->ClientOnionAuthDir);
+ tor_free(args);
+ tor_free(cp1);
+ buf_free(TO_CONN(&conn)->outbuf);
+ tor_free(conn.current_cmd);
+ tor_free(creds_fname);
+ tor_free(creds_file_str);
+ hs_client_free_all();
+}
+
+/** Test that ADD_ONION properly handles an attacker passing it a bad private
+ * key. */
+static void
+test_hs_control_add_onion_with_bad_pubkey(void *arg)
+{
+ (void) arg;
+
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+
+ int retval;
+ control_connection_t conn;
+ char *args = NULL;
+ char *cp1 = NULL;
+ size_t sz;
+
+ hs_init();
+
+ { /* Setup the control conn */
+ memset(&conn, 0, sizeof(control_connection_t));
+ TO_CONN(&conn)->outbuf = buf_new();
+ conn.current_cmd = tor_strdup("ADD_ONION");
+ }
+
+ args = tor_strdup("ED25519-V3:AAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
+ "Port=9735,127.0.0.1 Flags=DiscardPK");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check control port response */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "551 Failed to generate onion address\r\n");
+
+ done:
+ tor_free(args);
+ tor_free(cp1);
+ buf_free(TO_CONN(&conn)->outbuf);
+ tor_free(conn.current_cmd);
+}
+
struct testcase_t hs_control_tests[] = {
{ "hs_desc_event", test_hs_desc_event, TT_FORK,
NULL, NULL },
+ { "hs_control_good_onion_client_auth_add",
+ test_hs_control_good_onion_client_auth_add, TT_FORK,
+ NULL, NULL },
+ { "hs_control_bad_onion_client_auth_add",
+ test_hs_control_bad_onion_client_auth_add, TT_FORK,
+ NULL, NULL },
+ { "hs_control_store_permanent_creds",
+ test_hs_control_store_permanent_creds, TT_FORK, NULL, NULL },
+ { "hs_control_add_onion_with_bad_pubkey",
+ test_hs_control_add_onion_with_bad_pubkey, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index de584ed47a..b6e13c79a8 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "trunnel/ed25519_cert.h"
#include "core/or/or.h"
+#include "app/config/config.h"
#include "feature/hs/hs_descriptor.h"
#include "test/test.h"
#include "feature/nodelist/torcert.h"
@@ -21,21 +22,15 @@
#include "test/hs_test_helpers.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
+#include "test/rng_test_helpers.h"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-DISABLE_GCC_WARNING(overlength-strings)
+DISABLE_GCC_WARNING("-Woverlength-strings")
/* We allow huge string constants in the unit tests, but not in the code
* at large. */
#endif
#include "test_hs_descriptor.inc"
-ENABLE_GCC_WARNING(overlength-strings)
-
-/* Mock function to fill all bytes with 1 */
-static void
-mock_crypto_strongest_rand(uint8_t *out, size_t out_len)
-{
- memset(out, 1, out_len);
-}
+ENABLE_GCC_WARNING("-Woverlength-strings")
/* Test certificate encoding put in a descriptor. */
static void
@@ -43,7 +38,6 @@ test_cert_encoding(void *arg)
{
int ret;
char *encoded = NULL;
- time_t now = time(NULL);
ed25519_keypair_t kp;
ed25519_public_key_t signed_key;
ed25519_secret_key_t secret_key;
@@ -51,6 +45,10 @@ test_cert_encoding(void *arg)
(void) arg;
+ /* Change time to 03-01-2002 23:36 UTC */
+ update_approx_time(1010101010);
+ time_t now = approx_time();
+
ret = ed25519_keypair_generate(&kp, 0);
tt_int_op(ret, == , 0);
ret = ed25519_secret_key_generate(&secret_key, 0);
@@ -58,7 +56,7 @@ test_cert_encoding(void *arg)
ret = ed25519_public_key_generate(&signed_key, &secret_key);
tt_int_op(ret, == , 0);
- cert = tor_cert_create(&kp, CERT_TYPE_SIGNING_AUTH, &signed_key,
+ cert = tor_cert_create_ed25519(&kp, CERT_TYPE_SIGNING_AUTH, &signed_key,
now, 3600 * 2, CERT_FLAG_INCLUDE_SIGNING_KEY);
tt_assert(cert);
@@ -94,13 +92,31 @@ test_cert_encoding(void *arg)
/* The cert did have the signing key? */
ret= ed25519_pubkey_eq(&parsed_cert->signing_key, &kp.pubkey);
tt_int_op(ret, OP_EQ, 1);
- tor_cert_free(parsed_cert);
/* Get to the end part of the certificate. */
pos += b64_cert_len;
tt_int_op(strcmpstart(pos, "-----END ED25519 CERT-----"), OP_EQ, 0);
pos += strlen("-----END ED25519 CERT-----");
tt_str_op(pos, OP_EQ, "");
+
+ /* Check that certificate expiry works properly and emits the right log
+ message */
+ const char *msg = "fire";
+ /* Move us forward 4 hours so that the the certificate is definitely
+ expired */
+ update_approx_time(approx_time() + 3600*4);
+ setup_full_capture_of_logs(LOG_PROTOCOL_WARN);
+ ret = cert_is_valid(parsed_cert, CERT_TYPE_SIGNING_AUTH, msg);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Since the current time at the creation of the cert was "03-01-2002
+ * 23:36", and the expiration date of the cert was two hours, the Tor code
+ * will ceiling that and make it 02:00. Make sure that the right log
+ * message is emitted */
+ expect_log_msg_containing("Invalid signature for fire: expired"
+ " (2002-01-04 02:00:00)");
+ teardown_capture_of_logs();
+
+ tor_cert_free(parsed_cert);
}
done:
@@ -132,7 +148,7 @@ test_descriptor_padding(void *arg)
tt_assert(padded_plaintext);
tor_free(plaintext);
/* Make sure our padding has been zeroed. */
- tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len,
+ tt_int_op(fast_mem_is_zero((char *) padded_plaintext + plaintext_len,
padded_len - plaintext_len), OP_EQ, 1);
tor_free(padded_plaintext);
/* Never never have a padded length smaller than the plaintext. */
@@ -149,7 +165,7 @@ test_descriptor_padding(void *arg)
tt_assert(padded_plaintext);
tor_free(plaintext);
/* Make sure our padding has been zeroed. */
- tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len,
+ tt_int_op(fast_mem_is_zero((char *) padded_plaintext + plaintext_len,
padded_len - plaintext_len), OP_EQ, 1);
tor_free(padded_plaintext);
/* Never never have a padded length smaller than the plaintext. */
@@ -166,7 +182,7 @@ test_descriptor_padding(void *arg)
tt_assert(padded_plaintext);
tor_free(plaintext);
/* Make sure our padding has been zeroed. */
- tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len,
+ tt_int_op(fast_mem_is_zero((char *) padded_plaintext + plaintext_len,
padded_len - plaintext_len), OP_EQ, 1);
tor_free(padded_plaintext);
/* Never never have a padded length smaller than the plaintext. */
@@ -179,115 +195,6 @@ test_descriptor_padding(void *arg)
}
static void
-test_link_specifier(void *arg)
-{
- ssize_t ret;
- hs_desc_link_specifier_t spec;
- smartlist_t *link_specifiers = smartlist_new();
- char buf[256];
- char *b64 = NULL;
- link_specifier_t *ls = NULL;
-
- (void) arg;
-
- /* Always this port. */
- spec.u.ap.port = 42;
- smartlist_add(link_specifiers, &spec);
-
- /* Test IPv4 for starter. */
- {
- uint32_t ipv4;
-
- spec.type = LS_IPV4;
- ret = tor_addr_parse(&spec.u.ap.addr, "1.2.3.4");
- tt_int_op(ret, OP_EQ, AF_INET);
- b64 = encode_link_specifiers(link_specifiers);
- tt_assert(b64);
-
- /* Decode it and validate the format. */
- ret = base64_decode(buf, sizeof(buf), b64, strlen(b64));
- tt_int_op(ret, OP_GT, 0);
- /* First byte is the number of link specifier. */
- tt_int_op(get_uint8(buf), OP_EQ, 1);
- ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1);
- tt_int_op(ret, OP_EQ, 8);
- /* Should be 2 bytes for port and 4 bytes for IPv4. */
- tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, 6);
- ipv4 = link_specifier_get_un_ipv4_addr(ls);
- tt_int_op(tor_addr_to_ipv4h(&spec.u.ap.addr), OP_EQ, ipv4);
- tt_int_op(link_specifier_get_un_ipv4_port(ls), OP_EQ, spec.u.ap.port);
-
- link_specifier_free(ls);
- ls = NULL;
- tor_free(b64);
- }
-
- /* Test IPv6. */
- {
- uint8_t ipv6[16];
-
- spec.type = LS_IPV6;
- ret = tor_addr_parse(&spec.u.ap.addr, "[1:2:3:4::]");
- tt_int_op(ret, OP_EQ, AF_INET6);
- b64 = encode_link_specifiers(link_specifiers);
- tt_assert(b64);
-
- /* Decode it and validate the format. */
- ret = base64_decode(buf, sizeof(buf), b64, strlen(b64));
- tt_int_op(ret, OP_GT, 0);
- /* First byte is the number of link specifier. */
- tt_int_op(get_uint8(buf), OP_EQ, 1);
- ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1);
- tt_int_op(ret, OP_EQ, 20);
- /* Should be 2 bytes for port and 16 bytes for IPv6. */
- tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, 18);
- for (unsigned int i = 0; i < sizeof(ipv6); i++) {
- ipv6[i] = link_specifier_get_un_ipv6_addr(ls, i);
- }
- tt_mem_op(tor_addr_to_in6_addr8(&spec.u.ap.addr), OP_EQ, ipv6,
- sizeof(ipv6));
- tt_int_op(link_specifier_get_un_ipv6_port(ls), OP_EQ, spec.u.ap.port);
-
- link_specifier_free(ls);
- ls = NULL;
- tor_free(b64);
- }
-
- /* Test legacy. */
- {
- uint8_t *id;
-
- spec.type = LS_LEGACY_ID;
- memset(spec.u.legacy_id, 'Y', sizeof(spec.u.legacy_id));
- b64 = encode_link_specifiers(link_specifiers);
- tt_assert(b64);
-
- /* Decode it and validate the format. */
- ret = base64_decode(buf, sizeof(buf), b64, strlen(b64));
- tt_int_op(ret, OP_GT, 0);
- /* First byte is the number of link specifier. */
- tt_int_op(get_uint8(buf), OP_EQ, 1);
- ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1);
- /* 20 bytes digest + 1 byte type + 1 byte len. */
- tt_int_op(ret, OP_EQ, 22);
- tt_int_op(link_specifier_getlen_un_legacy_id(ls), OP_EQ, DIGEST_LEN);
- /* Digest length is 20 bytes. */
- tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, DIGEST_LEN);
- id = link_specifier_getarray_un_legacy_id(ls);
- tt_mem_op(spec.u.legacy_id, OP_EQ, id, DIGEST_LEN);
-
- link_specifier_free(ls);
- ls = NULL;
- tor_free(b64);
- }
-
- done:
- link_specifier_free(ls);
- tor_free(b64);
- smartlist_free(link_specifiers);
-}
-
-static void
test_encode_descriptor(void *arg)
{
int ret;
@@ -336,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;
@@ -345,19 +252,19 @@ 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, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
ret = hs_desc_encode_descriptor(desc, &signing_kp, NULL, &encoded);
- tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(encoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential, NULL, &decoded);
- tt_int_op(ret, OP_EQ, 0);
+ ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
hs_helper_desc_equal(desc, decoded);
@@ -368,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);
@@ -377,8 +284,8 @@ 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);
- tt_int_op(ret, OP_EQ, 0);
+ ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
}
@@ -401,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);
@@ -430,23 +337,23 @@ 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_LT, 0);
+ 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_LT, 0);
+ 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, 0);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
hs_helper_desc_equal(desc, decoded);
@@ -682,7 +589,7 @@ test_decode_bad_signature(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = hs_desc_decode_plaintext(HS_DESC_BAD_SIG, &desc_plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
expect_log_msg_containing("Malformed signature line. Rejecting.");
teardown_capture_of_logs();
@@ -722,14 +629,14 @@ test_decode_plaintext(void *arg)
tor_asprintf(&plaintext, template, bad_value, "180", "42", "MESSAGE");
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Missing fields. */
{
const char *plaintext = "hs-descriptor 3\n";
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Max length. */
@@ -742,7 +649,7 @@ test_decode_plaintext(void *arg)
plaintext[big - 1] = '\0';
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Bad lifetime value. */
@@ -751,7 +658,7 @@ test_decode_plaintext(void *arg)
tor_asprintf(&plaintext, template, "3", bad_value, "42", "MESSAGE");
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Huge lifetime value. */
@@ -760,7 +667,7 @@ test_decode_plaintext(void *arg)
tor_asprintf(&plaintext, template, "3", "7181615", "42", "MESSAGE");
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Invalid encrypted section. */
@@ -769,7 +676,7 @@ test_decode_plaintext(void *arg)
tor_asprintf(&plaintext, template, "3", "180", "42", bad_value);
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
/* Invalid revision counter. */
@@ -778,7 +685,7 @@ test_decode_plaintext(void *arg)
tor_asprintf(&plaintext, template, "3", "180", bad_value, "MESSAGE");
ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
tor_free(plaintext);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
}
done:
@@ -799,7 +706,7 @@ test_validate_cert(void *arg)
tt_int_op(ret, OP_EQ, 0);
/* Cert of type CERT_TYPE_AUTH_HS_IP_KEY. */
- cert = tor_cert_create(&kp, CERT_TYPE_AUTH_HS_IP_KEY,
+ cert = tor_cert_create_ed25519(&kp, CERT_TYPE_AUTH_HS_IP_KEY,
&kp.pubkey, now, 3600,
CERT_FLAG_INCLUDE_SIGNING_KEY);
tt_assert(cert);
@@ -819,8 +726,9 @@ test_validate_cert(void *arg)
tor_cert_free(cert);
/* Try a cert without including the signing key. */
- cert = tor_cert_create(&kp, CERT_TYPE_AUTH_HS_IP_KEY, &kp.pubkey, now,
- 3600, 0);
+ cert = tor_cert_create_ed25519(&kp, CERT_TYPE_AUTH_HS_IP_KEY,
+ &kp.pubkey, now, 3600, 0);
+
tt_assert(cert);
/* Test with a bad type. */
ret = cert_is_valid(cert, CERT_TYPE_AUTH_HS_IP_KEY, "unicorn");
@@ -848,8 +756,7 @@ test_desc_signature(void *arg)
ret = ed25519_sign_prefixed(&sig, (const uint8_t *) data, strlen(data),
"Tor onion service descriptor sig v3", &kp);
tt_int_op(ret, OP_EQ, 0);
- ret = ed25519_signature_to_base64(sig_b64, &sig);
- tt_int_op(ret, OP_EQ, 0);
+ ed25519_signature_to_base64(sig_b64, &sig);
/* Build the descriptor that should be valid. */
tor_asprintf(&desc, "%ssignature %s\n", data, sig_b64);
ret = desc_sig_is_valid(sig_b64, &kp.pubkey, desc, strlen(desc));
@@ -878,7 +785,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;
@@ -890,7 +797,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));
@@ -909,9 +816,9 @@ test_build_authorized_client(void *arg)
client_pubkey_b16,
strlen(client_pubkey_b16));
- MOCK(crypto_strongest_rand_, mock_crypto_strongest_rand);
+ 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);
@@ -925,15 +832,13 @@ test_build_authorized_client(void *arg)
done:
tor_free(desc_client);
tor_free(mem_op_hex_tmp);
- UNMOCK(crypto_strongest_rand_);
+ testing_disable_prefilled_rng();
}
struct testcase_t hs_descriptor[] = {
/* Encoding tests. */
{ "cert_encoding", test_cert_encoding, TT_FORK,
NULL, NULL },
- { "link_specifier", test_link_specifier, TT_FORK,
- NULL, NULL },
{ "encode_descriptor", test_encode_descriptor, TT_FORK,
NULL, NULL },
{ "descriptor_padding", test_descriptor_padding, TT_FORK,
diff --git a/src/test/test_hs_dos.c b/src/test/test_hs_dos.c
new file mode 100644
index 0000000000..642513efce
--- /dev/null
+++ b/src/test/test_hs_dos.c
@@ -0,0 +1,176 @@
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_cell.c
+ * \brief Test hidden service cell functionality.
+ */
+
+#define CIRCUITLIST_PRIVATE
+#define NETWORKSTATUS_PRIVATE
+#define HS_DOS_PRIVATE
+#define HS_INTROPOINT_PRIVATE
+
+#include "test/test.h"
+#include "test/test_helpers.h"
+#include "test/log_test_helpers.h"
+
+#include "app/config/config.h"
+
+#include "core/or/circuitlist.h"
+#include "core/or/circuituse.h"
+#include "core/or/or_circuit_st.h"
+
+#include "feature/hs/hs_dos.h"
+#include "feature/hs/hs_intropoint.h"
+#include "feature/nodelist/networkstatus.h"
+
+static void
+setup_mock_consensus(void)
+{
+ current_ns_consensus = tor_malloc_zero(sizeof(networkstatus_t));
+ current_ns_consensus->net_params = smartlist_new();
+ smartlist_add(current_ns_consensus->net_params,
+ (void *) "HiddenServiceEnableIntroDoSDefense=1");
+ hs_dos_consensus_has_changed(current_ns_consensus);
+}
+
+static void
+free_mock_consensus(void)
+{
+ smartlist_free(current_ns_consensus->net_params);
+ tor_free(current_ns_consensus);
+}
+
+static void
+test_can_send_intro2(void *arg)
+{
+ uint32_t now = (uint32_t) approx_time();
+ or_circuit_t *or_circ = NULL;
+
+ (void) arg;
+
+ hs_init();
+ hs_dos_init();
+
+ get_options_mutable()->ORPort_set = 1;
+ setup_mock_consensus();
+
+ or_circ = or_circuit_new(1, NULL);
+
+ /* Make that circuit a service intro point. */
+ circuit_change_purpose(TO_CIRCUIT(or_circ), CIRCUIT_PURPOSE_INTRO_POINT);
+ hs_dos_setup_default_intro2_defenses(or_circ);
+ or_circ->introduce2_dos_defense_enabled = 1;
+
+ /* Brand new circuit, we should be able to send INTRODUCE2 cells. */
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+
+ /* Simulate that 10 cells have arrived in 1 second. There should be no
+ * refill since the bucket is already at maximum on the first cell. */
+ update_approx_time(++now);
+ for (int i = 0; i < 10; i++) {
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ }
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
+ get_intro2_burst_consensus_param(NULL) - 10);
+
+ /* Fully refill the bucket minus 1 cell. */
+ update_approx_time(++now);
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
+ get_intro2_burst_consensus_param(NULL) - 1);
+
+ /* Receive an INTRODUCE2 at each second. We should have the bucket full
+ * since at every second it gets refilled. */
+ for (int i = 0; i < 10; i++) {
+ update_approx_time(++now);
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ }
+ /* Last check if we can send the cell decrements the bucket so minus 1. */
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
+ get_intro2_burst_consensus_param(NULL) - 1);
+
+ /* Manually reset bucket for next test. */
+ token_bucket_ctr_reset(&or_circ->introduce2_bucket, now);
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
+ get_intro2_burst_consensus_param(NULL));
+
+ /* Do a full burst in the current second which should empty the bucket and
+ * we shouldn't be allowed to send one more cell after that. We go minus 1
+ * cell else the very last check if we can send the INTRO2 cell returns
+ * false because the bucket goes down to 0. */
+ for (uint32_t i = 0; i < get_intro2_burst_consensus_param(NULL) - 1; i++) {
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ }
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, 1);
+ /* Get the last remaining cell, we shouldn't be allowed to send it. */
+ tt_int_op(false, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, 0);
+
+ /* Make sure the next 100 cells aren't allowed and bucket stays at 0. */
+ for (int i = 0; i < 100; i++) {
+ tt_int_op(false, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, 0);
+ }
+
+ /* One second has passed, we should have the rate minus 1 cell added. */
+ update_approx_time(++now);
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
+ get_intro2_rate_consensus_param(NULL) - 1);
+
+ done:
+ circuit_free_(TO_CIRCUIT(or_circ));
+
+ hs_free_all();
+ free_mock_consensus();
+}
+
+static void
+test_validate_dos_extension_params(void *arg)
+{
+ bool ret;
+
+ (void) arg;
+
+ /* Validate the default values. */
+ ret = cell_dos_extension_parameters_are_valid(
+ get_intro2_rate_consensus_param(NULL),
+ get_intro2_burst_consensus_param(NULL));
+ tt_assert(ret);
+
+ /* Valid custom rate/burst. */
+ ret = cell_dos_extension_parameters_are_valid(17, 42);
+ tt_assert(ret);
+ ret = cell_dos_extension_parameters_are_valid(INT32_MAX, INT32_MAX);
+ tt_assert(ret);
+
+ /* Invalid rate. */
+ ret = cell_dos_extension_parameters_are_valid(UINT64_MAX, 42);
+ tt_assert(!ret);
+
+ /* Invalid burst. */
+ ret = cell_dos_extension_parameters_are_valid(42, UINT64_MAX);
+ tt_assert(!ret);
+
+ /* Value of 0 is valid (but should disable defenses) */
+ ret = cell_dos_extension_parameters_are_valid(0, 0);
+ tt_assert(ret);
+
+ /* Can't have burst smaller than rate. */
+ ret = cell_dos_extension_parameters_are_valid(42, 40);
+ tt_assert(!ret);
+
+ done:
+ return;
+}
+
+struct testcase_t hs_dos_tests[] = {
+ { "can_send_intro2", test_can_send_intro2, TT_FORK,
+ NULL, NULL },
+ { "validate_dos_extension_params", test_validate_dos_extension_params,
+ TT_FORK, NULL, NULL },
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index 9493da2995..5f7dfc4f84 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,6 +16,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "core/or/or.h"
+#include "core/or/channel.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "ht.h"
@@ -25,6 +26,8 @@
#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_circuitmap.h"
#include "feature/hs/hs_common.h"
+#include "feature/hs/hs_config.h"
+#include "feature/hs/hs_dos.h"
#include "feature/hs/hs_intropoint.h"
#include "feature/hs/hs_service.h"
@@ -43,6 +46,9 @@ new_establish_intro_cell(const char *circ_nonce,
uint8_t buf[RELAY_PAYLOAD_SIZE] = {0};
trn_cell_establish_intro_t *cell = NULL;
hs_service_intro_point_t *ip = NULL;
+ hs_service_config_t config;
+
+ memset(&config, 0, sizeof(config));
/* Ensure that *cell_out is NULL such that we can use to check if we need to
* free `cell` in case of an error. */
@@ -50,9 +56,9 @@ new_establish_intro_cell(const char *circ_nonce,
/* Auth key pair is generated in the constructor so we are all set for
* using this IP object. */
- ip = service_intro_point_new(NULL, 0, 0);
+ ip = service_intro_point_new(NULL);
tt_assert(ip);
- cell_len = hs_cell_build_establish_intro(circ_nonce, ip, buf);
+ cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, buf);
tt_i64_op(cell_len, OP_GT, 0);
cell_len = trn_cell_establish_intro_parse(&cell, buf, sizeof(buf));
@@ -73,12 +79,15 @@ new_establish_intro_encoded_cell(const char *circ_nonce, uint8_t *cell_out)
{
ssize_t cell_len = 0;
hs_service_intro_point_t *ip = NULL;
+ hs_service_config_t config;
+
+ memset(&config, 0, sizeof(config));
/* Auth key pair is generated in the constructor so we are all set for
* using this IP object. */
- ip = service_intro_point_new(NULL, 0, 0);
+ ip = service_intro_point_new(NULL);
tt_assert(ip);
- cell_len = hs_cell_build_establish_intro(circ_nonce, ip, cell_out);
+ cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell_out);
tt_i64_op(cell_len, OP_GT, 0);
done:
@@ -118,6 +127,8 @@ helper_create_intro_circuit(void)
or_circuit_t *circ = or_circuit_new(0, NULL);
tt_assert(circ);
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
+ token_bucket_ctr_init(&circ->introduce2_bucket, 100, 100,
+ (uint32_t) approx_time());
done:
return circ;
}
@@ -629,6 +640,17 @@ test_introduce1_suitable_circuit(void *arg)
tt_int_op(ret, OP_EQ, 0);
}
+ /* Single hop circuit should not be allowed. */
+ {
+ circ = or_circuit_new(0, NULL);
+ circ->p_chan = tor_malloc_zero(sizeof(channel_t));
+ circ->p_chan->is_client = 1;
+ ret = circuit_is_suitable_for_introduce1(circ);
+ tor_free(circ->p_chan);
+ circuit_free_(TO_CIRCUIT(circ));
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
done:
;
}
@@ -671,12 +693,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);
@@ -824,43 +849,213 @@ test_received_introduce1_handling(void *arg)
UNMOCK(relay_send_command_from_edge_);
}
+static void
+test_received_establish_intro_dos_ext(void *arg)
+{
+ int ret;
+ ssize_t cell_len = 0;
+ uint8_t cell[RELAY_PAYLOAD_SIZE] = {0};
+ char circ_nonce[DIGEST_LEN] = {0};
+ hs_service_intro_point_t *ip = NULL;
+ hs_service_config_t config;
+ or_circuit_t *intro_circ = or_circuit_new(0,NULL);
+
+ (void) arg;
+
+ MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
+
+ hs_circuitmap_init();
+
+ /* Setup. */
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+ ip = service_intro_point_new(NULL);
+ tt_assert(ip);
+ ip->support_intro2_dos_defense = 1;
+ memset(&config, 0, sizeof(config));
+ config.has_dos_defense_enabled = 1;
+ config.intro_dos_rate_per_sec = 13;
+ config.intro_dos_burst_per_sec = 42;
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+ /* The INTRO2 bucket should be 0 at this point. */
+ tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ, 0);
+ tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ, 0);
+ tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ, 0);
+ tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ, 0);
+
+ /* Case 1: Build encoded cell. Usable DoS parameters. */
+ cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell);
+ tt_size_op(cell_len, OP_GT, 0);
+ /* Pass it to the intro point. */
+ ret = hs_intro_received_establish_intro(intro_circ, cell, cell_len);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Should be set to the burst value. */
+ tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ, 42);
+ /* Validate the config of the intro2 bucket. */
+ tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ, 13);
+ tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ, 42);
+ tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ, 1);
+
+ /* Need to reset the circuit in between test cases. */
+ circuit_free_(TO_CIRCUIT(intro_circ));
+ intro_circ = or_circuit_new(0,NULL);
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Case 2: Build encoded cell. Bad DoS parameters. */
+ config.has_dos_defense_enabled = 1;
+ config.intro_dos_rate_per_sec = UINT_MAX;
+ config.intro_dos_burst_per_sec = 13;
+ cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell);
+ tt_size_op(cell_len, OP_GT, 0);
+ /* Pass it to the intro point. */
+ ret = hs_intro_received_establish_intro(intro_circ, cell, cell_len);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
+ tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT);
+ tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
+ tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_DEFAULT);
+
+ /* Need to reset the circuit in between test cases. */
+ circuit_free_(TO_CIRCUIT(intro_circ));
+ intro_circ = or_circuit_new(0,NULL);
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Case 3: Build encoded cell. Burst is smaller than rate. Not allowed. */
+ config.has_dos_defense_enabled = 1;
+ config.intro_dos_rate_per_sec = 87;
+ config.intro_dos_burst_per_sec = 45;
+ cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell);
+ tt_size_op(cell_len, OP_GT, 0);
+ /* Pass it to the intro point. */
+ ret = hs_intro_received_establish_intro(intro_circ, cell, cell_len);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
+ tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT);
+ tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
+ tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_DEFAULT);
+
+ /* Need to reset the circuit in between test cases. */
+ circuit_free_(TO_CIRCUIT(intro_circ));
+ intro_circ = or_circuit_new(0,NULL);
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Case 4: Build encoded cell. Rate is 0 but burst is not 0. Disables the
+ * defense. */
+ config.has_dos_defense_enabled = 1;
+ config.intro_dos_rate_per_sec = 0;
+ config.intro_dos_burst_per_sec = 45;
+ cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell);
+ tt_size_op(cell_len, OP_GT, 0);
+ /* Pass it to the intro point. */
+ ret = hs_intro_received_establish_intro(intro_circ, cell, cell_len);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
+ tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT);
+ tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
+ tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_DEFAULT);
+
+ /* Need to reset the circuit in between test cases. */
+ circuit_free_(TO_CIRCUIT(intro_circ));
+ intro_circ = or_circuit_new(0,NULL);
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Case 5: Build encoded cell. Burst is 0 but rate is not 0. Disables the
+ * defense. */
+ config.has_dos_defense_enabled = 1;
+ config.intro_dos_rate_per_sec = 45;
+ config.intro_dos_burst_per_sec = 0;
+ cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, cell);
+ tt_size_op(cell_len, OP_GT, 0);
+ /* Pass it to the intro point. */
+ ret = hs_intro_received_establish_intro(intro_circ, cell, cell_len);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_u64_op(token_bucket_ctr_get(&intro_circ->introduce2_bucket), OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
+ tt_u64_op(intro_circ->introduce2_bucket.cfg.rate, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT);
+ tt_int_op(intro_circ->introduce2_bucket.cfg.burst, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT);
+ tt_int_op(intro_circ->introduce2_dos_defense_enabled, OP_EQ,
+ HS_CONFIG_V3_DOS_DEFENSE_DEFAULT);
+
+ done:
+ circuit_free_(TO_CIRCUIT(intro_circ));
+ service_intro_point_free(ip);
+ hs_circuitmap_free_all();
+ UNMOCK(relay_send_command_from_edge_);
+}
+
+static void *
+hs_subsystem_setup_fn(const struct testcase_t *tc)
+{
+ (void) tc;
+
+ return NULL;
+}
+
+static int
+hs_subsystem_cleanup_fn(const struct testcase_t *tc, void *arg)
+{
+ (void) tc;
+ (void) arg;
+
+ return 1;
+}
+
+static struct testcase_setup_t test_setup = {
+ hs_subsystem_setup_fn, hs_subsystem_cleanup_fn
+};
+
struct testcase_t hs_intropoint_tests[] = {
{ "intro_point_registration",
- test_intro_point_registration, TT_FORK, NULL, NULL },
+ test_intro_point_registration, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_keytype",
- test_establish_intro_wrong_keytype, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_keytype, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_keytype2",
- test_establish_intro_wrong_keytype2, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_keytype2, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_purpose",
- test_establish_intro_wrong_purpose, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_purpose, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_sig",
- test_establish_intro_wrong_sig, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_sig, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_sig_len",
- test_establish_intro_wrong_sig_len, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_sig_len, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_auth_key_len",
- test_establish_intro_wrong_auth_key_len, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_auth_key_len, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_mac",
- test_establish_intro_wrong_mac, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_mac, TT_FORK, NULL, &test_setup},
{ "introduce1_suitable_circuit",
- test_introduce1_suitable_circuit, TT_FORK, NULL, NULL },
+ test_introduce1_suitable_circuit, TT_FORK, NULL, &test_setup},
{ "introduce1_is_legacy",
- test_introduce1_is_legacy, TT_FORK, NULL, NULL },
+ test_introduce1_is_legacy, TT_FORK, NULL, &test_setup},
{ "introduce1_validation",
- test_introduce1_validation, TT_FORK, NULL, NULL },
+ test_introduce1_validation, TT_FORK, NULL, &test_setup},
{ "received_introduce1_handling",
- test_received_introduce1_handling, TT_FORK, NULL, NULL },
+ test_received_introduce1_handling, TT_FORK, NULL, &test_setup},
+
+ { "received_establish_intro_dos_ext",
+ test_received_establish_intro_dos_ext, TT_FORK, NULL, &test_setup},
END_OF_TESTCASES
};
-
diff --git a/src/test/test_hs_metrics.c b/src/test/test_hs_metrics.c
new file mode 100644
index 0000000000..326212ae1d
--- /dev/null
+++ b/src/test/test_hs_metrics.c
@@ -0,0 +1,68 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_metrics.c
+ * \brief Test hidden service metrics.
+ */
+
+#define HS_SERVICE_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_metrics.h"
+#include "feature/hs/hs_service.h"
+
+#include "lib/crypt_ops/crypto_ed25519.h"
+
+static void
+test_metrics(void *arg)
+{
+ hs_service_t *service = NULL;
+
+ (void) arg;
+
+ hs_init();
+
+ 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(get_hs_service_map(), service);
+
+ tt_assert(service->metrics.store);
+
+ /* Update entry by identifier. */
+ hs_metrics_update_by_ident(HS_METRICS_NUM_INTRODUCTIONS,
+ &service->keys.identity_pk, 0, 42);
+
+ /* Confirm the entry value. */
+ const smartlist_t *entries = metrics_store_get_all(service->metrics.store,
+ "tor_hs_intro_num_total");
+ tt_assert(entries);
+ tt_int_op(smartlist_len(entries), OP_EQ, 1);
+ const metrics_store_entry_t *entry = smartlist_get(entries, 0);
+ tt_assert(entry);
+ tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 42);
+
+ /* Update entry by service now. */
+ hs_metrics_update_by_service(HS_METRICS_NUM_INTRODUCTIONS,
+ service, 0, 42);
+ tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 84);
+
+ done:
+ hs_free_all();
+}
+
+struct testcase_t hs_metrics_tests[] = {
+
+ { "metrics", test_metrics, TT_FORK, NULL, NULL },
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_hs_ntor.c b/src/test/test_hs_ntor.c
index 1c694e6040..7867740a1a 100644
--- a/src/test/test_hs_ntor.c
+++ b/src/test/test_hs_ntor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -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.sh b/src/test/test_hs_ntor.sh
index 8a0003d44a..ee7141cc9a 100755
--- a/src/test/test_hs_ntor.sh
+++ b/src/test/test_hs_ntor.sh
@@ -3,7 +3,7 @@
exitcode=0
-# Run the python integration test sand return the exitcode of the python
+# Run the python integration tests and return the exitcode of the python
# script. The python script might ask the testsuite to skip it if not all
# python dependencies are covered.
"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/hs_ntor_ref.py" || exitcode=$?
diff --git a/src/test/test_hs_ntor_cl.c b/src/test/test_hs_ntor_cl.c
index 6341b96d84..3acd7ef0bc 100644
--- a/src/test/test_hs_ntor_cl.c
+++ b/src/test/test_hs_ntor_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** This is a wrapper over the little-t-tor HS ntor functions. The wrapper is
@@ -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 3a3ef0c01a..287d25f825 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,8 +19,9 @@
#define MAINLOOP_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define STATEFILE_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define HS_CLIENT_PRIVATE
+#define CRYPT_PATH_PRIVATE
#include "test/test.h"
#include "test/test_helpers.h"
@@ -43,14 +44,17 @@
#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_metrics.h"
#include "feature/hs/hs_service.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
@@ -60,6 +64,7 @@
#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
+#include "core/or/crypt_path.h"
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/node_st.h"
#include "core/or/origin_circuit_st.h"
@@ -86,6 +91,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) */
@@ -108,6 +121,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,
@@ -123,11 +139,29 @@ 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;
}
/* Helper: from a set of options in conf, configure a service which will add
- * it to the staging list of the HS subsytem. */
+ * it to the staging list of the HS subsystem. */
static int
helper_config_service(const char *conf)
{
@@ -170,8 +204,7 @@ test_e2e_rend_circuit_setup(void *arg)
tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0));
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk));
- or_circ->hs_ident = hs_ident_circuit_new(&service_pk,
- HS_IDENT_CIRCUIT_RENDEZVOUS);
+ or_circ->hs_ident = hs_ident_circuit_new(&service_pk);
TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
}
@@ -183,9 +216,8 @@ test_e2e_rend_circuit_setup(void *arg)
/* Setup the circuit: do the ntor key exchange */
{
uint8_t ntor_key_seed[DIGEST256_LEN] = {2};
- retval = hs_circuit_setup_e2e_rend_circ(or_circ,
- ntor_key_seed, sizeof(ntor_key_seed),
- 1);
+ retval = hs_circuit_setup_e2e_rend_circ(or_circ, ntor_key_seed,
+ sizeof(ntor_key_seed), 1);
tt_int_op(retval, OP_EQ, 0);
}
@@ -194,12 +226,12 @@ test_e2e_rend_circuit_setup(void *arg)
tt_int_op(retval, OP_EQ, 1);
/* Check the digest algo */
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.f_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest),
OP_EQ, DIGEST_SHA3_256);
- tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.b_digest),
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest),
OP_EQ, DIGEST_SHA3_256);
- tt_assert(or_circ->cpath->crypto.f_crypto);
- tt_assert(or_circ->cpath->crypto.b_crypto);
+ tt_assert(or_circ->cpath->pvt_crypto.f_crypto);
+ tt_assert(or_circ->cpath->pvt_crypto.b_crypto);
/* Ensure that circ purpose was changed */
tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_S_REND_JOINED);
@@ -268,7 +300,7 @@ helper_clone_authorized_client(const hs_service_authorized_client_t *client)
/* Helper: Return a newly allocated service object with the identity keypair
* sets and the current descriptor. Then register it to the global map.
- * Caller should us hs_free_all() to free this service or remove it from the
+ * Caller should use hs_free_all() to free this service or remove it from the
* global map before freeing. */
static hs_service_t *
helper_create_service(void)
@@ -290,6 +322,20 @@ helper_create_service(void)
return service;
}
+/* Helper: Deallocate a given service object, its child objects and
+ * remove it from onion service map.
+ * */
+static void
+helper_destroy_service(hs_service_t *service)
+{
+ if (!service)
+ return;
+
+ remove_service(get_hs_service_map(), service);
+
+ hs_service_free(service);
+}
+
/* Helper: Return a newly allocated service object with clients. */
static hs_service_t *
helper_create_service_with_clients(int num_clients)
@@ -315,17 +361,18 @@ helper_create_service_with_clients(int num_clients)
static hs_service_intro_point_t *
helper_create_service_ip(void)
{
- hs_desc_link_specifier_t *ls;
- hs_service_intro_point_t *ip = service_intro_point_new(NULL, 0, 0);
+ link_specifier_t *ls;
+ hs_service_intro_point_t *ip = service_intro_point_new(NULL);
tor_assert(ip);
/* Add a first unused link specifier. */
- ls = tor_malloc_zero(sizeof(*ls));
- ls->type = LS_IPV4;
+ ls = link_specifier_new();
+ link_specifier_set_ls_type(ls, LS_IPV4);
smartlist_add(ip->base.link_specifiers, ls);
/* Add a second link specifier used by a test. */
- ls = tor_malloc_zero(sizeof(*ls));
- ls->type = LS_LEGACY_ID;
- memset(ls->u.legacy_id, 'A', sizeof(ls->u.legacy_id));
+ ls = link_specifier_new();
+ link_specifier_set_ls_type(ls, LS_LEGACY_ID);
+ memset(link_specifier_getarray_un_legacy_id(ls), 'A',
+ link_specifier_getlen_un_legacy_id(ls));
smartlist_add(ip->base.link_specifiers, ls);
return ip;
@@ -376,11 +423,11 @@ test_load_keys(void *arg)
tt_assert(s);
/* Ok we have the service object. Validate few things. */
- tt_assert(!tor_mem_is_zero(s->onion_address, sizeof(s->onion_address)));
+ tt_assert(!fast_mem_is_zero(s->onion_address, sizeof(s->onion_address)));
tt_int_op(hs_address_is_valid(s->onion_address), OP_EQ, 1);
- tt_assert(!tor_mem_is_zero((char *) s->keys.identity_sk.seckey,
+ tt_assert(!fast_mem_is_zero((char *) s->keys.identity_sk.seckey,
ED25519_SECKEY_LEN));
- tt_assert(!tor_mem_is_zero((char *) s->keys.identity_pk.pubkey,
+ tt_assert(!fast_mem_is_zero((char *) s->keys.identity_pk.pubkey,
ED25519_PUBKEY_LEN));
/* Check onion address from identity key. */
hs_build_address(&s->keys.identity_pk, s->config.version, addr);
@@ -617,6 +664,7 @@ test_access_service(void *arg)
tt_mem_op(query, OP_EQ, s, sizeof(hs_service_t));
/* Remove service, check if it actually works and then put it back. */
remove_service(global_map, s);
+ hs_metrics_service_free(s);
tt_int_op(get_hs_service_map_size(), OP_EQ, 0);
query = find_service(global_map, &s->keys.identity_pk);
tt_ptr_op(query, OP_EQ, NULL);
@@ -626,6 +674,7 @@ test_access_service(void *arg)
tt_int_op(ret, OP_EQ, 0);
tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
/* Twice should fail. */
+ hs_metrics_service_free(s); /* Avoid BUG() on metrics init. */
ret = register_service(global_map, s);
tt_int_op(ret, OP_EQ, -1);
/* Remove service from map so we don't double free on cleanup. */
@@ -654,13 +703,15 @@ test_service_intro_point(void *arg)
(void) arg;
+ update_approx_time(1481621834);
+
/* Test simple creation of an object. */
{
- time_t now = time(NULL);
+ time_t now = approx_time();
ip = helper_create_service_ip();
tt_assert(ip);
/* Make sure the authentication keypair is not zeroes. */
- tt_int_op(tor_mem_is_zero((const char *) &ip->auth_key_kp,
+ tt_int_op(fast_mem_is_zero((const char *) &ip->auth_key_kp,
sizeof(ed25519_keypair_t)), OP_EQ, 0);
/* The introduce2_max MUST be in that range. */
tt_u64_op(ip->introduce2_max, OP_GE,
@@ -726,7 +777,7 @@ mock_node_get_by_id(const char *digest)
{
(void) digest;
memset(mock_node.identity, 'A', DIGEST_LEN);
- /* Only return the matchin identity of As */
+ /* Only return the matching identity of As */
if (!tor_memcmp(mock_node.identity, digest, DIGEST_LEN)) {
return &mock_node;
}
@@ -795,10 +846,11 @@ test_helper_functions(void *arg)
const node_t *node = get_node_from_intro_point(ip);
tt_ptr_op(node, OP_EQ, &mock_node);
SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers,
- hs_desc_link_specifier_t *, ls) {
- if (ls->type == LS_LEGACY_ID) {
+ link_specifier_t *, ls) {
+ if (link_specifier_get_ls_type(ls) == LS_LEGACY_ID) {
/* Change legacy id in link specifier which is not the mock node. */
- memset(ls->u.legacy_id, 'B', sizeof(ls->u.legacy_id));
+ memset(link_specifier_getarray_un_legacy_id(ls), 'B',
+ link_specifier_getlen_un_legacy_id(ls));
}
} SMARTLIST_FOREACH_END(ls);
node = get_node_from_intro_point(ip);
@@ -856,6 +908,10 @@ test_helper_functions(void *arg)
done:
/* This will free the service and all objects associated to it. */
+ if (service) {
+ remove_service(get_hs_service_map(), service);
+ hs_service_free(service);
+ }
hs_service_free_all();
UNMOCK(node_get_by_id);
}
@@ -865,7 +921,7 @@ static void
test_intro_circuit_opened(void *arg)
{
int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
- hs_service_t *service;
+ hs_service_t *service = NULL;
origin_circuit_t *circ = NULL;
(void) arg;
@@ -913,6 +969,10 @@ test_intro_circuit_opened(void *arg)
done:
circuit_free_(TO_CIRCUIT(circ));
+ if (service) {
+ remove_service(get_hs_service_map(), service);
+ hs_service_free(service);
+ }
hs_free_all();
UNMOCK(circuit_mark_for_close_);
UNMOCK(relay_send_command_from_edge_);
@@ -927,7 +987,7 @@ test_intro_established(void *arg)
int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
uint8_t payload[RELAY_PAYLOAD_SIZE] = {0};
origin_circuit_t *circ = NULL;
- hs_service_t *service;
+ hs_service_t *service = NULL;
hs_service_intro_point_t *ip = NULL;
(void) arg;
@@ -982,12 +1042,15 @@ test_intro_established(void *arg)
/* Send an empty payload. INTRO_ESTABLISHED cells are basically zeroes. */
ret = hs_service_receive_intro_established(circ, payload, sizeof(payload));
tt_int_op(ret, OP_EQ, 0);
- tt_u64_op(ip->circuit_established, OP_EQ, 1);
tt_int_op(TO_CIRCUIT(circ)->purpose, OP_EQ, CIRCUIT_PURPOSE_S_INTRO);
done:
if (circ)
circuit_free_(TO_CIRCUIT(circ));
+ if (service) {
+ remove_service(get_hs_service_map(), service);
+ hs_service_free(service);
+ }
hs_free_all();
UNMOCK(circuit_mark_for_close_);
}
@@ -999,7 +1062,7 @@ test_rdv_circuit_opened(void *arg)
{
int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
origin_circuit_t *circ = NULL;
- hs_service_t *service;
+ hs_service_t *service = NULL;
(void) arg;
@@ -1030,6 +1093,10 @@ test_rdv_circuit_opened(void *arg)
done:
circuit_free_(TO_CIRCUIT(circ));
+ if (service) {
+ remove_service(get_hs_service_map(), service);
+ hs_service_free(service);
+ }
hs_free_all();
UNMOCK(circuit_mark_for_close_);
UNMOCK(relay_send_command_from_edge_);
@@ -1067,8 +1134,7 @@ test_closing_intro_circs(void *arg)
/* Initialize intro circuit */
intro_circ = origin_circuit_init(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, flags);
- intro_circ->hs_ident = hs_ident_circuit_new(&service->keys.identity_pk,
- HS_IDENT_CIRCUIT_INTRO);
+ intro_circ->hs_ident = hs_ident_circuit_new(&service->keys.identity_pk);
/* Register circuit in the circuitmap . */
hs_circuitmap_register_intro_circ_v3_service_side(intro_circ,
&ip->auth_key_kp.pubkey);
@@ -1094,8 +1160,7 @@ test_closing_intro_circs(void *arg)
/* Now pretend that a new intro point circ was launched and opened. Check
* that the intro point will be established correctly. */
intro_circ = origin_circuit_init(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, flags);
- intro_circ->hs_ident = hs_ident_circuit_new(&service->keys.identity_pk,
- HS_IDENT_CIRCUIT_INTRO);
+ intro_circ->hs_ident = hs_ident_circuit_new(&service->keys.identity_pk);
ed25519_pubkey_copy(&intro_circ->hs_ident->intro_auth_pk,
&ip->auth_key_kp.pubkey);
/* Register circuit in the circuitmap . */
@@ -1117,19 +1182,23 @@ test_closing_intro_circs(void *arg)
circuit_free_(TO_CIRCUIT(intro_circ));
}
/* Frees the service object. */
+ if (service) {
+ remove_service(get_hs_service_map(), service);
+ hs_service_free(service);
+ }
hs_free_all();
UNMOCK(assert_circuit_ok);
}
/** 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;
uint8_t payload[RELAY_PAYLOAD_SIZE] = {0};
origin_circuit_t *circ = NULL;
- hs_service_t *service;
+ hs_service_t *service = NULL;
hs_service_intro_point_t *ip = NULL;
(void) arg;
@@ -1139,7 +1208,7 @@ test_introduce2(void *arg)
MOCK(get_or_state,
get_or_state_replacement);
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_S_INTRO, flags);
tt_assert(circ);
@@ -1196,6 +1265,10 @@ test_introduce2(void *arg)
dummy_state = NULL;
if (circ)
circuit_free_(TO_CIRCUIT(circ));
+ if (service) {
+ remove_service(get_hs_service_map(), service);
+ hs_service_free(service);
+ }
hs_free_all();
UNMOCK(circuit_mark_for_close_);
}
@@ -1219,6 +1292,7 @@ test_service_event(void *arg)
/* Set a service for this circuit. */
service = helper_create_service();
+ tt_assert(service);
ed25519_pubkey_copy(&circ->hs_ident->identity_pk,
&service->keys.identity_pk);
@@ -1250,7 +1324,6 @@ test_service_event(void *arg)
* descriptor map so we can retry it. */
ip = helper_create_service_ip();
service_intro_point_add(service->desc_current->intro_points.map, ip);
- ip->circuit_established = 1; /* We'll test that, it MUST be 0 after. */
run_housekeeping_event(now);
tt_int_op(digest256map_size(service->desc_current->intro_points.map),
OP_EQ, 1);
@@ -1280,6 +1353,10 @@ test_service_event(void *arg)
done:
hs_circuitmap_remove_circuit(TO_CIRCUIT(circ));
circuit_free_(TO_CIRCUIT(circ));
+ if (service) {
+ remove_service(get_hs_service_map(), service);
+ hs_service_free(service);
+ }
hs_free_all();
UNMOCK(circuit_mark_for_close_);
}
@@ -1290,12 +1367,12 @@ test_rotate_descriptors(void *arg)
{
int ret;
time_t next_rotation_time, now;
- hs_service_t *service;
+ hs_service_t *service = NULL;
hs_service_descriptor_t *desc_next;
(void) arg;
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
hs_init();
MOCK(get_or_state, get_or_state_replacement);
@@ -1311,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;
@@ -1352,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;
@@ -1382,6 +1459,10 @@ test_rotate_descriptors(void *arg)
tt_assert(service->desc_next);
done:
+ if (service) {
+ remove_service(get_hs_service_map(), service);
+ hs_service_free(service);
+ }
hs_free_all();
UNMOCK(get_or_state);
UNMOCK(circuit_mark_for_close_);
@@ -1394,9 +1475,8 @@ static void
test_build_update_descriptors(void *arg)
{
int ret;
- time_t now = time(NULL);
node_t *node;
- hs_service_t *service;
+ hs_service_t *service = NULL;
hs_service_intro_point_t *ip_cur, *ip_next;
routerinfo_t ri;
@@ -1409,7 +1489,7 @@ test_build_update_descriptors(void *arg)
MOCK(networkstatus_get_reasonably_live_consensus,
mock_networkstatus_get_reasonably_live_consensus);
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
ret = parse_rfc1123_time("Sat, 26 Oct 1985 03:00:00 UTC",
&mock_ns.valid_after);
@@ -1417,10 +1497,11 @@ 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);
- now = mock_ns.valid_after+1;
+
+ time_t now = mock_ns.valid_after+1;
/* Create a service without a current descriptor to trigger a build. */
service = helper_create_service();
@@ -1466,14 +1547,12 @@ test_build_update_descriptors(void *arg)
/* Now, we'll setup a node_t. */
{
- tor_addr_t ipv4_addr;
curve25519_secret_key_t curve25519_secret_key;
memset(&ri, 0, sizeof(routerinfo_t));
- tor_addr_parse(&ipv4_addr, "127.0.0.1");
- ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
- ri.or_port = 1337;
+ tor_addr_parse(&ri.ipv4_addr, "127.0.0.1");
+ ri.ipv4_orport = 1337;
ri.purpose = ROUTER_PURPOSE_GENERAL;
/* Ugly yes but we never free the "ri" object so this just makes things
* easier. */
@@ -1540,13 +1619,13 @@ test_build_update_descriptors(void *arg)
/* We won't test the service IP object because there is a specific test
* already for this but we'll make sure that the state is coherent.*/
- /* Three link specifiers are mandatoy so make sure we do have them. */
+ /* Three link specifiers are mandatory so make sure we do have them. */
tt_int_op(smartlist_len(ip_cur->base.link_specifiers), OP_EQ, 3);
/* Make sure we have a valid encryption keypair generated when we pick an
* intro point in the update process. */
- tt_assert(!tor_mem_is_zero((char *) ip_cur->enc_key_kp.seckey.secret_key,
+ tt_assert(!fast_mem_is_zero((char *) ip_cur->enc_key_kp.seckey.secret_key,
CURVE25519_SECKEY_LEN));
- tt_assert(!tor_mem_is_zero((char *) ip_cur->enc_key_kp.pubkey.public_key,
+ tt_assert(!fast_mem_is_zero((char *) ip_cur->enc_key_kp.pubkey.public_key,
CURVE25519_PUBKEY_LEN));
tt_u64_op(ip_cur->time_to_expire, OP_GE, now +
INTRO_POINT_LIFETIME_MIN_SECONDS);
@@ -1612,6 +1691,10 @@ test_build_update_descriptors(void *arg)
tt_u64_op(service->desc_next->next_upload_time, OP_EQ, 0);
done:
+ if (service) {
+ remove_service(get_hs_service_map(), service);
+ hs_service_free(service);
+ }
hs_free_all();
nodelist_free_all();
}
@@ -1624,6 +1707,7 @@ test_build_descriptors(void *arg)
{
int ret;
time_t now = time(NULL);
+ hs_service_t *last_service = NULL;
(void) arg;
@@ -1634,7 +1718,7 @@ test_build_descriptors(void *arg)
MOCK(networkstatus_get_reasonably_live_consensus,
mock_networkstatus_get_reasonably_live_consensus);
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
ret = parse_rfc1123_time("Sat, 26 Oct 1985 03:00:00 UTC",
&mock_ns.valid_after);
@@ -1642,25 +1726,33 @@ 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. */
{
hs_service_t *service = helper_create_service();
+ last_service = service;
service_descriptor_free(service->desc_current);
service->desc_current = NULL;
build_all_descriptors(now);
+ tt_assert(service->desc_current);
+ tt_assert(service->desc_current->desc);
+
hs_desc_superencrypted_data_t *superencrypted;
superencrypted = &service->desc_current->desc->superencrypted_data;
tt_int_op(smartlist_len(superencrypted->clients), OP_EQ, 16);
+
+ helper_destroy_service(service);
+ last_service = NULL;
}
/* Generate a valid number of fake auth clients when the number of
* clients is zero. */
{
hs_service_t *service = helper_create_service_with_clients(0);
+ last_service = service;
service_descriptor_free(service->desc_current);
service->desc_current = NULL;
@@ -1668,12 +1760,16 @@ test_build_descriptors(void *arg)
hs_desc_superencrypted_data_t *superencrypted;
superencrypted = &service->desc_current->desc->superencrypted_data;
tt_int_op(smartlist_len(superencrypted->clients), OP_EQ, 16);
+
+ helper_destroy_service(service);
+ last_service = NULL;
}
/* Generate a valid number of fake auth clients when the number of
* clients is not a multiple of 16. */
{
hs_service_t *service = helper_create_service_with_clients(20);
+ last_service = service;
service_descriptor_free(service->desc_current);
service->desc_current = NULL;
@@ -1681,12 +1777,16 @@ test_build_descriptors(void *arg)
hs_desc_superencrypted_data_t *superencrypted;
superencrypted = &service->desc_current->desc->superencrypted_data;
tt_int_op(smartlist_len(superencrypted->clients), OP_EQ, 32);
+
+ helper_destroy_service(service);
+ last_service = NULL;
}
/* Do not generate any fake desc client when the number of clients is
* a multiple of 16 but not zero. */
{
hs_service_t *service = helper_create_service_with_clients(32);
+ last_service = service;
service_descriptor_free(service->desc_current);
service->desc_current = NULL;
@@ -1694,9 +1794,13 @@ test_build_descriptors(void *arg)
hs_desc_superencrypted_data_t *superencrypted;
superencrypted = &service->desc_current->desc->superencrypted_data;
tt_int_op(smartlist_len(superencrypted->clients), OP_EQ, 32);
+
+ helper_destroy_service(service);
+ last_service = NULL;
}
done:
+ helper_destroy_service(last_service);
hs_free_all();
}
@@ -1715,7 +1819,7 @@ test_upload_descriptors(void *arg)
MOCK(networkstatus_get_reasonably_live_consensus,
mock_networkstatus_get_reasonably_live_consensus);
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
&mock_ns.valid_after);
@@ -1723,7 +1827,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;
@@ -1845,9 +1949,9 @@ test_rendezvous1_parsing(void *arg)
}
/* Send out the RENDEZVOUS1 and make sure that our mock func worked */
- tt_assert(tor_mem_is_zero(rend1_payload, 32));
+ tt_assert(fast_mem_is_zero(rend1_payload, 32));
hs_circ_service_rp_has_opened(service, service_circ);
- tt_assert(!tor_mem_is_zero(rend1_payload, 32));
+ tt_assert(!fast_mem_is_zero(rend1_payload, 32));
tt_int_op(rend1_payload_len, OP_EQ, HS_LEGACY_RENDEZVOUS_CELL_SIZE);
/******************************/
@@ -2095,6 +2199,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 },
@@ -2120,7 +2708,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 },
@@ -2132,12 +2720,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_include.py b/src/test/test_include.py
new file mode 100644
index 0000000000..ec261da86c
--- /dev/null
+++ b/src/test/test_include.py
@@ -0,0 +1,196 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import errno
+import logging
+import os
+import random
+import socket
+import subprocess
+import sys
+import time
+import re
+
+CONTROL_SOCK_TIMEOUT = 10.0
+LOG_TIMEOUT = 60.0
+LOG_WAIT = 0.1
+
+def fail(msg):
+ logging.error('FAIL')
+ sys.exit(msg)
+
+def skip(msg):
+ logging.warning('SKIP: {}'.format(msg))
+ sys.exit(77)
+
+def wait_for_log(s):
+ cutoff = time.time() + LOG_TIMEOUT
+ while time.time() < cutoff:
+ l = tor_process.stdout.readline()
+ l = l.decode('utf8', 'backslashreplace')
+ if s in l:
+ logging.info('Tor logged: "{}"'.format(l.strip()))
+ return
+ # readline() returns a blank string when there is no output
+ # avoid busy-waiting
+ if len(l) == 0:
+ logging.debug('Tor has not logged anything, waiting for "{}"'.format(s))
+ time.sleep(LOG_WAIT)
+ else:
+ logging.info('Tor logged: "{}", waiting for "{}"'.format(l.strip(), s))
+ fail('Could not find "{}" in logs after {} seconds'.format(s, LOG_TIMEOUT))
+
+def pick_random_port():
+ port = 0
+ random.seed()
+
+ for i in range(8):
+ port = random.randint(10000, 60000)
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ if s.connect_ex(('127.0.0.1', port)) == 0:
+ s.close()
+ else:
+ break
+
+ if port == 0:
+ fail('Could not find a random free port between 10000 and 60000')
+
+ return port
+
+def check_control_list(control_out_file, expected, value_name):
+ received_count = 0
+ for e in expected:
+ received = control_out_file.readline().strip()
+ received_count += 1
+ parts = re.split('[ =-]', received.strip())
+ if len(parts) != 3 or parts[0] != '250' or parts[1] != value_name or parts[2] != e:
+ fail('Unexpected value in response line "{}". Expected {} for value {}'.format(received, e, value_name))
+ if received.startswith('250 '):
+ break
+
+ if received_count != len(expected):
+ fail('Expected response with {} lines but received {} lines'.format(len(expected), received_count))
+
+
+logging.basicConfig(level=logging.DEBUG,
+ format='%(asctime)s.%(msecs)03d %(message)s',
+ datefmt='%Y-%m-%d %H:%M:%S')
+
+if sys.hexversion < 0x02070000:
+ fail("ERROR: unsupported Python version (should be >= 2.7)")
+
+if sys.hexversion > 0x03000000 and sys.hexversion < 0x03010000:
+ fail("ERROR: unsupported Python3 version (should be >= 3.1)")
+
+if 'TOR_SKIP_TEST_INCLUDE' in os.environ:
+ skip('$TOR_SKIP_TEST_INCLUDE is set')
+
+control_port = pick_random_port()
+
+assert control_port != 0
+
+if len(sys.argv) < 4:
+ fail('Usage: %s <path-to-tor> <data-dir> <torrc>' % sys.argv[0])
+
+if not os.path.exists(sys.argv[1]):
+ fail('ERROR: cannot find tor at %s' % sys.argv[1])
+if not os.path.exists(sys.argv[2]):
+ fail('ERROR: cannot find datadir at %s' % sys.argv[2])
+if not os.path.exists(sys.argv[3]):
+ fail('ERROR: cannot find torrcdir at %s' % sys.argv[3])
+
+tor_path = sys.argv[1]
+data_dir = sys.argv[2]
+torrc_dir = sys.argv[3]
+
+empty_torrc_path = os.path.join(data_dir, 'empty_torrc')
+open(empty_torrc_path, 'w').close()
+empty_defaults_torrc_path = os.path.join(data_dir, 'empty_defaults_torrc')
+open(empty_defaults_torrc_path, 'w').close()
+torrc = os.path.join(torrc_dir, 'torrc')
+
+tor_process = subprocess.Popen([tor_path,
+ '-DataDirectory', data_dir,
+ '-ControlPort', '127.0.0.1:{}'.format(control_port),
+ '-Log', 'info stdout',
+ '-LogTimeGranularity', '1',
+ '-FetchServerDescriptors', '0',
+ '-DisableNetwork', '1',
+ '-f', torrc,
+ '--defaults-torrc', empty_defaults_torrc_path,
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+if tor_process == None:
+ fail('ERROR: running tor failed')
+
+wait_for_log('Opened Control listener')
+
+control_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+if control_socket.connect_ex(('127.0.0.1', control_port)):
+ tor_process.terminate()
+ fail('Cannot connect to ControlPort')
+control_socket.settimeout(CONTROL_SOCK_TIMEOUT)
+control_out_file = control_socket.makefile('r')
+
+control_socket.sendall('AUTHENTICATE \r\n'.encode('ascii'))
+res = control_out_file.readline().strip()
+if res != '250 OK':
+ tor_process.terminate()
+ fail('Cannot authenticate. Response was: {}'.format(res))
+
+# test configuration file values and order
+control_socket.sendall('GETCONF NodeFamily\r\n'.encode('ascii'))
+check_control_list(control_out_file, ['1', '2', '3', '4', '5', '6', '4' , '5'], 'NodeFamily')
+
+# test reloading the configuration file with seccomp sandbox enabled
+foo_path = os.path.join(torrc_dir, 'torrc.d', 'foo')
+with open(foo_path, 'a') as foo:
+ foo.write('NodeFamily 7')
+
+control_socket.sendall('SIGNAL RELOAD\r\n'.encode('ascii'))
+wait_for_log('Reloading config and resetting internal state.')
+res = control_out_file.readline().strip()
+if res != '250 OK':
+ tor_process.terminate()
+ fail('Cannot reload configuration. Response was: {}'.format(res))
+
+
+control_socket.sendall('GETCONF NodeFamily\r\n'.encode('ascii'))
+check_control_list(control_out_file, ['1', '2', '3', '4', '5', '6', '7', '4' , '5'], 'NodeFamily')
+
+# test that config-can-saveconf is 0 because we have a %include
+control_socket.sendall('getinfo config-can-saveconf\r\n'.encode('ascii'))
+res = control_out_file.readline().strip()
+if res != '250-config-can-saveconf=0':
+ tor_process.terminate()
+ fail('getinfo config-can-saveconf returned wrong response: {}'.format(res))
+else:
+ res = control_out_file.readline().strip()
+ if res != '250 OK':
+ tor_process.terminate()
+ fail('getinfo failed. Response was: {}'.format(res))
+
+# test that saveconf returns error because we have a %include
+control_socket.sendall('SAVECONF\r\n'.encode('ascii'))
+res = control_out_file.readline().strip()
+if res != '551 Unable to write configuration to disk.':
+ tor_process.terminate()
+ fail('SAVECONF returned wrong response. Response was: {}'.format(res))
+
+control_socket.sendall('SIGNAL HALT\r\n'.encode('ascii'))
+
+wait_for_log('exiting cleanly')
+logging.info('OK')
+
+try:
+ tor_process.terminate()
+except OSError as e:
+ if e.errno == errno.ESRCH: # errno 3: No such process
+ # assume tor has already exited due to SIGNAL HALT
+ logging.warn("Tor has already exited")
+ else:
+ raise
diff --git a/src/test/test_include.sh b/src/test/test_include.sh
new file mode 100755
index 0000000000..6cf695fe44
--- /dev/null
+++ b/src/test/test_include.sh
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+umask 077
+set -e
+set -x
+
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
+UNAME_OS=$(uname -s | cut -d_ -f1)
+if test "$UNAME_OS" = 'CYGWIN' || \
+ test "$UNAME_OS" = 'MSYS' || \
+ test "$UNAME_OS" = 'MINGW' || \
+ test "$UNAME_OS" = 'MINGW32' || \
+ test "$UNAME_OS" = 'MINGW64'; then
+ if test "$APPVEYOR" = 'True'; then
+ echo "This test is disabled on Windows CI, as it requires firewall exemptions. Skipping." >&2
+ exit 77
+ fi
+fi
+
+# find the tor binary
+if [ $# -ge 1 ]; then
+ TOR_BINARY="${1}"
+ shift
+else
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+if "${TOR_BINARY}" --list-modules | grep -q "relay: no"; then
+ echo "This test requires the relay module. Skipping." >&2
+ exit 77
+fi
+
+tmpdir=
+clean () {
+ if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then
+ rm -rf "$tmpdir"
+ fi
+}
+
+trap clean EXIT HUP INT TERM
+
+tmpdir="$(mktemp -d -t tor_include_test.XXXXXX)"
+if [ -z "$tmpdir" ]; then
+ echo >&2 mktemp failed
+ exit 2
+elif [ ! -d "$tmpdir" ]; then
+ echo >&2 mktemp failed to make a directory
+ exit 3
+fi
+
+datadir="$tmpdir/data"
+mkdir "$datadir"
+
+configdir="$tmpdir/config"
+mkdir "$configdir"
+
+# translate paths to windows format
+if test "$UNAME_OS" = 'CYGWIN' || \
+ test "$UNAME_OS" = 'MSYS' || \
+ test "$UNAME_OS" = 'MINGW' || \
+ test "$UNAME_OS" = 'MINGW32' || \
+ test "$UNAME_OS" = 'MINGW64'; then
+ datadir=$(cygpath --windows "$datadir")
+ configdir=$(cygpath --windows "$configdir")
+fi
+
+# create test folder structure in configdir
+torrcd="$configdir/torrc.d"
+mkdir "$torrcd"
+mkdir "$torrcd/folder"
+mkdir "$torrcd/empty_folder"
+echo "NodeFamily 1" > "$torrcd/01_one.conf"
+echo "NodeFamily 2" > "$torrcd/02_two.conf"
+echo "NodeFamily 3" > "$torrcd/aa_three.conf"
+echo "NodeFamily 42" > "$torrcd/.hidden.conf"
+echo "NodeFamily 6" > "$torrcd/foo"
+touch "$torrcd/empty.conf"
+echo "# comment" > "$torrcd/comment.conf"
+echo "NodeFamily 4" > "$torrcd/folder/04_four.conf"
+echo "NodeFamily 5" > "$torrcd/folder/05_five.conf"
+torrc="$configdir/torrc"
+echo "Sandbox 1" > "$torrc"
+echo "
+%include $torrcd/*.conf
+%include $torrcd/f*
+%include $torrcd/*/*
+%include $torrcd/empty_folder
+%include $torrcd/empty.conf
+%include $torrcd/comment.conf
+" >> "$torrc"
+
+"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/test_include.py" "${TOR_BINARY}" "$datadir" "$configdir"
+
+exit $?
diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c
index 4a6d90d97e..0ae78496b2 100644
--- a/src/test/test_introduce.c
+++ b/src/test/test_introduce.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -383,8 +383,10 @@ make_intro_from_plaintext(
/* Output the cell */
*cell_out = cell;
+ cell = NULL;
done:
+ tor_free(cell);
return cell_len;
}
@@ -535,4 +537,3 @@ struct testcase_t introduce_tests[] = {
INTRODUCE_LEGACY(late_parse_v3),
END_OF_TESTCASES
};
-
diff --git a/src/test/test_key_expiration.sh b/src/test/test_key_expiration.sh
index 3474210607..1ba8179aa1 100755
--- a/src/test/test_key_expiration.sh
+++ b/src/test/test_key_expiration.sh
@@ -6,14 +6,28 @@
umask 077
set -e
-if [ $# -eq 0 ] || [ ! -f ${1} ] || [ ! -x ${1} ]; then
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
+if [ $# -eq 0 ] || [ ! -f "${1}" ] || [ ! -x "${1}" ]; then
if [ "$TESTING_TOR_BINARY" = "" ] ; then
echo "Usage: ${0} PATH_TO_TOR [case-number]"
exit 1
fi
fi
-UNAME_OS=`uname -s | cut -d_ -f1`
+UNAME_OS=$(uname -s | cut -d_ -f1)
if test "$UNAME_OS" = 'CYGWIN' || \
test "$UNAME_OS" = 'MSYS' || \
test "$UNAME_OS" = 'MINGW'; then
@@ -21,11 +35,21 @@ if test "$UNAME_OS" = 'CYGWIN' || \
exit 77
fi
+# find the tor binary
if [ $# -ge 1 ]; then
TOR_BINARY="${1}"
shift
else
- TOR_BINARY="${TESTING_TOR_BINARY}"
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+if "$TOR_BINARY" --list-modules | grep -q "relay: no"; then
+ echo "This test requires the relay module. Skipping." >&2
+ exit 77
fi
if [ $# -ge 1 ]; then
@@ -37,6 +61,11 @@ fi
CASE1=$dflt
CASE2=$dflt
CASE3=$dflt
+CASE4=$dflt
+CASE5=$dflt
+CASE6=$dflt
+CASE7=$dflt
+CASE8=$dflt
if [ $# -ge 1 ]; then
eval "CASE${1}"=1
@@ -47,11 +76,11 @@ dump() { xxd -p "$1" | tr -d '\n '; }
die() { echo "$1" >&2 ; exit 5; }
check_dir() { [ -d "$1" ] || die "$1 did not exist"; }
check_file() { [ -e "$1" ] || die "$1 did not exist"; }
-check_no_file() { [ -e "$1" ] && die "$1 was not supposed to exist" || true; }
-check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: `dump $1` vs `dump $2`"; }
+check_no_file() { if [ -e "$1" ]; then die "$1 was not supposed to exist"; fi }
+check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: $(dump "$1") vs $(dump "$2")"; }
check_keys_eq() { check_files_eq "${SRC}/keys/${1}" "${ME}/keys/${1}"; }
-DATA_DIR=`mktemp -d -t tor_key_expiration_tests.XXXXXX`
+DATA_DIR=$(mktemp -d -t tor_key_expiration_tests.XXXXXX)
if [ -z "$DATA_DIR" ]; then
echo "Failure: mktemp invocation returned empty string" >&2
exit 3
@@ -60,10 +89,10 @@ if [ ! -d "$DATA_DIR" ]; then
echo "Failure: mktemp invocation result doesn't point to directory" >&2
exit 3
fi
-trap "rm -rf '$DATA_DIR'" 0
+trap 'rm -rf "$DATA_DIR"' 0
# Use an absolute path for this or Tor will complain
-DATA_DIR=`cd "${DATA_DIR}" && pwd`
+DATA_DIR=$(cd "${DATA_DIR}" && pwd)
touch "${DATA_DIR}/empty_torrc"
touch "${DATA_DIR}/empty_defaults_torrc"
@@ -101,16 +130,17 @@ if [ "$CASE1" = 1 ]; then
${TOR} ${QUIETLY} --key-expiration 2>"$FN" || true
grep "No valid argument to --key-expiration found!" "$FN" >/dev/null || \
- die "Tor didn't mention supported --key-expiration argmuents"
+ die "Tor didn't mention supported --key-expiration arguments"
echo "==== Case 1: ok"
fi
if [ "$CASE2" = 1 ]; then
- echo "==== Case 2: Start Tor with --key-expiration 'sign' and make sure it prints an expiration."
+ echo "==== Case 2: Start Tor with --key-expiration 'sign' and make sure it"
+ echo " prints an expiration using ISO8601 date format."
${TOR} ${QUIETLY} --key-expiration sign 2>"$FN"
- grep "signing-cert-expiry:" "$FN" >/dev/null || \
+ grep "signing-cert-expiry: [0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} [0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}" "$FN" >/dev/null || \
die "Tor didn't print an expiration"
echo "==== Case 2: ok"
@@ -136,3 +166,61 @@ if [ "$CASE3" = 1 ]; then
echo "==== Case 3: ok"
fi
+
+if [ "$CASE4" = 1 ]; then
+ echo "==== Case 4: Start Tor with --format iso8601 and make sure it prints an"
+ echo " error message due to missing --key-expiration argument."
+
+ ${TOR} --format iso8601 > "$FN" 2>&1 || true
+ grep -- "--format specified without --key-expiration!" "$FN" >/dev/null || \
+ die "Tor didn't print a missing --key-expiration error message"
+
+ echo "==== Case 4: ok"
+fi
+
+if [ "$CASE5" = 1 ]; then
+ echo "==== Case 5: Start Tor with --key-expiration 'sign' --format '' and"
+ echo " make sure it prints an error message due to missing value."
+
+ ${TOR} --key-expiration sign --format > "$FN" 2>&1 || true
+ grep "Command-line option '--format' with no value. Failing." "$FN" >/dev/null || \
+ die "Tor didn't print a missing format value error message"
+
+ echo "==== Case 5: ok"
+fi
+
+if [ "$CASE6" = 1 ]; then
+ echo "==== Case 6: Start Tor with --key-expiration 'sign' --format 'invalid'"
+ echo " and make sure it prints an error message due to invalid"
+ echo " value."
+
+ ${TOR} --key-expiration sign --format invalid > "$FN" 2>&1 || true
+ grep "Invalid --format value" "$FN" >/dev/null || \
+ die "Tor didn't print an invalid format value error message"
+
+ echo "==== Case 6: ok"
+fi
+
+if [ "$CASE7" = 1 ]; then
+ echo "==== Case 7: Start Tor with --key-expiration 'sign' --format 'iso8601'"
+ echo " and make sure it prints an expiration using ISO8601 date"
+ echo " format."
+
+ ${TOR} ${QUIETLY} --key-expiration sign --format iso8601 2>"$FN"
+ grep "signing-cert-expiry: [0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} [0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}" "$FN" >/dev/null || \
+ die "Tor didn't print an expiration"
+
+ echo "==== Case 7: ok"
+fi
+
+if [ "$CASE8" = 1 ]; then
+ echo "==== Case 8: Start Tor with --key-expiration 'sign' --format 'timestamp'"
+ echo " and make sure it prints an expiration using timestamp date"
+ echo " format."
+
+ ${TOR} ${QUIETLY} --key-expiration sign --format timestamp 2>"$FN"
+ grep "signing-cert-expiry: [0-9]\{5,\}" "$FN" >/dev/null || \
+ die "Tor didn't print an expiration"
+
+ echo "==== Case 8: ok"
+fi
diff --git a/src/test/test_keygen.sh b/src/test/test_keygen.sh
index 7afff271cb..6812f8883d 100755
--- a/src/test/test_keygen.sh
+++ b/src/test/test_keygen.sh
@@ -6,14 +6,28 @@
umask 077
set -e
-if [ $# -eq 0 ] || [ ! -f ${1} ] || [ ! -x ${1} ]; then
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
+if [ $# -eq 0 ] || [ ! -f "${1}" ] || [ ! -x "${1}" ]; then
if [ "$TESTING_TOR_BINARY" = "" ] ; then
echo "Usage: ${0} PATH_TO_TOR [case-number]"
exit 1
fi
fi
-UNAME_OS=`uname -s | cut -d_ -f1`
+UNAME_OS=$(uname -s | cut -d_ -f1)
if test "$UNAME_OS" = 'CYGWIN' || \
test "$UNAME_OS" = 'MSYS' || \
test "$UNAME_OS" = 'MINGW'; then
@@ -21,14 +35,22 @@ if test "$UNAME_OS" = 'CYGWIN' || \
exit 77
fi
+# find the tor binary
if [ $# -ge 1 ]; then
TOR_BINARY="${1}"
shift
else
- TOR_BINARY="${TESTING_TOR_BINARY}"
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
fi
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+if "$TOR_BINARY" --list-modules | grep -q "relay: no"; then
+ echo "This test requires the relay module. Skipping." >&2
+ exit 77
+fi
if [ $# -ge 1 ]; then
dflt=0
@@ -64,11 +86,11 @@ dump() { xxd -p "$1" | tr -d '\n '; }
die() { echo "$1" >&2 ; exit 5; }
check_dir() { [ -d "$1" ] || die "$1 did not exist"; }
check_file() { [ -e "$1" ] || die "$1 did not exist"; }
-check_no_file() { [ -e "$1" ] && die "$1 was not supposed to exist" || true; }
-check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: `dump $1` vs `dump $2`"; }
+check_no_file() { if [ -e "$1" ]; then die "$1 was not supposed to exist"; fi }
+check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: $(dump "$1") vs $(dump "$2")"; }
check_keys_eq() { check_files_eq "${SRC}/keys/${1}" "${ME}/keys/${1}"; }
-DATA_DIR=`mktemp -d -t tor_keygen_tests.XXXXXX`
+DATA_DIR=$(mktemp -d -t tor_keygen_tests.XXXXXX)
if [ -z "$DATA_DIR" ]; then
echo "Failure: mktemp invocation returned empty string" >&2
exit 3
@@ -77,10 +99,10 @@ if [ ! -d "$DATA_DIR" ]; then
echo "Failure: mktemp invocation result doesn't point to directory" >&2
exit 3
fi
-trap "rm -rf '$DATA_DIR'" 0
+trap 'rm -rf "$DATA_DIR"' 0
# Use an absolute path for this or Tor will complain
-DATA_DIR=`cd "${DATA_DIR}" && pwd`
+DATA_DIR=$(cd "${DATA_DIR}" && pwd)
touch "${DATA_DIR}/empty_torrc"
touch "${DATA_DIR}/empty_defaults_torrc"
@@ -144,7 +166,9 @@ ME="${DATA_DIR}/case2a"
SRC="${DATA_DIR}/orig"
mkdir -p "${ME}/keys"
cp "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/"
-${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/stdout" && die "Somehow succeeded when missing secret key, certs: `cat ${ME}/stdout`" || true
+if ${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/stdout"; then
+ die "Somehow succeeded when missing secret key, certs: $(cat "${ME}/stdout")"
+fi
check_files_eq "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/ed25519_master_id_public_key"
grep "We needed to load a secret key.*but couldn't find it" "${ME}/stdout" >/dev/null || die "Tor didn't declare that it was missing a secret key"
@@ -281,7 +305,9 @@ SRC="${DATA_DIR}/encrypted"
mkdir -p "${ME}/keys"
cp "${SRC}/keys/ed25519_master_id_secret_key_encrypted" "${ME}/keys/"
cp "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/"
-${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/stdout" && die "Tor started with encrypted secret key and no certs" || true
+if ${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/stdout"; then
+ die "Tor started with encrypted secret key and no certs"
+fi
check_no_file "${ME}/keys/ed25519_signing_cert"
check_no_file "${ME}/keys/ed25519_signing_secret_key"
@@ -370,7 +396,9 @@ mkdir -p "${ME}/keys"
cp "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/"
cp "${OTHER}/keys/ed25519_master_id_secret_key" "${ME}/keys/"
-${TOR} --DataDirectory "${ME}" --list-fingerprint >"${ME}/stdout" && die "Successfully started with mismatched keys!?" || true
+if ${TOR} --DataDirectory "${ME}" --list-fingerprint >"${ME}/stdout"; then
+ die "Successfully started with mismatched keys!?"
+fi
grep "public_key does not match.*secret_key" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a key mismatch"
@@ -386,7 +414,9 @@ ME="${DATA_DIR}/case11a"
mkdir -p "${ME}/keys"
-${TOR} --DataDirectory "${ME}" --passphrase-fd 1 > "${ME}/stdout" && die "Successfully started with passphrase-fd but no keygen?" || true
+if ${TOR} --DataDirectory "${ME}" --passphrase-fd 1 > "${ME}/stdout"; then
+ die "Successfully started with passphrase-fd but no keygen?"
+fi
grep "passphrase-fd specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
@@ -402,7 +432,9 @@ ME="${DATA_DIR}/case11b"
mkdir -p "${ME}/keys"
-${TOR} --DataDirectory "${ME}" --no-passphrase > "${ME}/stdout" && die "Successfully started with no-passphrase but no keygen?" || true
+if ${TOR} --DataDirectory "${ME}" --no-passphrase > "${ME}/stdout"; then
+ die "Successfully started with no-passphrase but no keygen?"
+fi
grep "no-passphrase specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
@@ -418,7 +450,9 @@ ME="${DATA_DIR}/case11C"
mkdir -p "${ME}/keys"
-${TOR} --DataDirectory "${ME}" --newpass > "${ME}/stdout" && die "Successfully started with newpass but no keygen?" || true
+if ${TOR} --DataDirectory "${ME}" --newpass > "${ME}/stdout"; then
+ die "Successfully started with newpass but no keygen?"
+fi
grep "newpass specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
@@ -456,7 +490,9 @@ ME="${DATA_DIR}/case11E"
mkdir -p "${ME}/keys"
-${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd ewigeblumenkraft > "${ME}/stdout" && die "Successfully started with bogus passphrase-fd?" || true
+if ${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd ewigeblumenkraft > "${ME}/stdout"; then
+ die "Successfully started with bogus passphrase-fd?"
+fi
grep "Invalid --passphrase-fd value" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
@@ -473,7 +509,9 @@ ME="${DATA_DIR}/case11F"
mkdir -p "${ME}/keys"
-${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd 1 --no-passphrase > "${ME}/stdout" && die "Successfully started with bogus passphrase-fd combination?" || true
+if ${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd 1 --no-passphrase > "${ME}/stdout"; then
+ die "Successfully started with bogus passphrase-fd combination?"
+fi
grep "no-passphrase specified with --passphrase-fd" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
diff --git a/src/test/test_keypin.c b/src/test/test_keypin.c
index e7beef8609..ff6397f8c7 100644
--- a/src/test/test_keypin.c
+++ b/src/test/test_keypin.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index 34f59f26cd..06af299056 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -1,11 +1,11 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define CHANNELTLS_PRIVATE
#define CONNECTION_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_OBJECT_PRIVATE
#define TORTLS_PRIVATE
#include "core/or/or.h"
@@ -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"
@@ -263,7 +264,7 @@ test_link_handshake_certs_ok(void *arg)
tt_assert(c1->handshake_state->authenticated_rsa);
tt_assert(! c1->handshake_state->authenticated_ed25519);
}
- tt_assert(! tor_mem_is_zero(
+ tt_assert(! fast_mem_is_zero(
(char*)c1->handshake_state->authenticated_rsa_peer_id, 20));
chan2 = tor_malloc_zero(sizeof(*chan2));
@@ -290,7 +291,7 @@ test_link_handshake_certs_ok(void *arg)
tt_ptr_op(c2->handshake_state->certs->ed_id_sign, OP_EQ, NULL);
}
tt_assert(c2->handshake_state->certs->id_cert);
- tt_assert(tor_mem_is_zero(
+ tt_assert(fast_mem_is_zero(
(char*)c2->handshake_state->authenticated_rsa_peer_id, 20));
/* no authentication has happened yet, since we haen't gotten an AUTH cell.
*/
@@ -325,7 +326,7 @@ test_link_handshake_certs_ok(void *arg)
crypto_pk_free(key2);
}
-typedef struct certs_data_s {
+typedef struct certs_data_t {
int is_ed;
int is_link_cert;
or_connection_t *c;
@@ -709,7 +710,7 @@ CERTS_FAIL(missing_signing_key, /* ed25519 */
* signing key. */
const ed25519_keypair_t *mk = get_master_identity_keypair();
const ed25519_keypair_t *sk = get_master_signing_keypair();
- tor_cert_t *bad_cert = tor_cert_create(mk, CERT_TYPE_ID_SIGNING,
+ tor_cert_t *bad_cert = tor_cert_create_ed25519(mk, CERT_TYPE_ID_SIGNING,
&sk->pubkey, time(NULL), 86400,
0 /* don't include signer */);
certs_cell_cert_setlen_body(cert, bad_cert->encoded_len);
@@ -948,7 +949,7 @@ test_link_handshake_send_authchallenge(void *arg)
#else
tt_int_op(36, OP_EQ, cell1->payload_len);
tt_int_op(36, OP_EQ, cell2->payload_len);
-#endif
+#endif /* defined(HAVE_WORKING_TOR_TLS_GET_TLSSECRETS) */
tt_int_op(0, OP_EQ, cell1->circ_id);
tt_int_op(0, OP_EQ, cell2->circ_id);
tt_int_op(CELL_AUTH_CHALLENGE, OP_EQ, cell1->command);
@@ -960,7 +961,7 @@ test_link_handshake_send_authchallenge(void *arg)
#else
tt_mem_op("\x00\x01\x00\x03", OP_EQ, cell1->payload + 32, 4);
tt_mem_op("\x00\x01\x00\x03", OP_EQ, cell2->payload + 32, 4);
-#endif
+#endif /* defined(HAVE_WORKING_TOR_TLS_GET_TLSSECRETS) */
tt_mem_op(cell1->payload, OP_NE, cell2->payload, 32);
done:
@@ -972,7 +973,7 @@ test_link_handshake_send_authchallenge(void *arg)
crypto_pk_free(rsa1);
}
-typedef struct authchallenge_data_s {
+typedef struct authchallenge_data_t {
or_connection_t *c;
channel_tls_t *chan;
var_cell_t *cell;
@@ -1171,7 +1172,7 @@ mock_set_circid_type(channel_t *chan,
(void) consider_identity;
}
-typedef struct authenticate_data_s {
+typedef struct authenticate_data_t {
int is_ed;
or_connection_t *c1, *c2;
channel_tls_t *chan2;
@@ -1492,6 +1493,7 @@ AUTHENTICATE_FAIL(missing_ed_auth,
"authentication certificate";
})
+#ifndef COCCI
#define TEST_RSA(name, flags) \
{ #name , test_link_handshake_ ## name, (flags), \
&passthrough_setup, (void*)"RSA" }
@@ -1527,6 +1529,7 @@ AUTHENTICATE_FAIL(missing_ed_auth,
#define TEST_AUTHENTICATE_ED(name) \
{ "authenticate/" #name "_ed25519" , test_link_handshake_auth_ ## name, \
TT_FORK, &setup_authenticate, (void*)3 }
+#endif /* !defined(COCCI) */
struct testcase_t link_handshake_tests[] = {
TEST_RSA(certs_ok, TT_FORK),
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index 95a2fce757..58d0f24bd3 100644
--- a/src/test/test_logging.c
+++ b/src/test/test_logging.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
@@ -9,14 +9,13 @@
#include "lib/err/torerr.h"
#include "lib/log/log.h"
#include "test/test.h"
-#include "lib/process/subprocess.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
static void
-dummy_cb_fn(int severity, uint32_t domain, const char *msg)
+dummy_cb_fn(int severity, log_domain_mask_t domain, const char *msg)
{
(void)severity; (void)domain; (void)msg;
}
@@ -36,7 +35,7 @@ test_get_sigsafe_err_fds(void *arg)
set_log_severity_config(LOG_WARN, LOG_ERR, &include_bug);
set_log_severity_config(LOG_WARN, LOG_ERR, &no_bug);
- no_bug.masks[0] &= ~(LD_BUG|LD_GENERAL);
+ no_bug.masks[SEVERITY_MASK_IDX(LOG_ERR)] &= ~(LD_BUG|LD_GENERAL);
set_log_severity_config(LOG_INFO, LOG_NOTICE, &no_bug2);
/* Add some logs; make sure the output is as expected. */
@@ -117,22 +116,27 @@ test_sigsafe_err(void *arg)
content = read_file_to_str(fn, 0, NULL);
tt_ptr_op(content, OP_NE, NULL);
- tor_split_lines(lines, content, (int)strlen(content));
+ smartlist_split_string(lines, content, "\n", 0, 0);
tt_int_op(smartlist_len(lines), OP_GE, 5);
- if (strstr(smartlist_get(lines, 0), "opening new log file"))
+ if (strstr(smartlist_get(lines, 0), "opening new log file")) {
+ void *item = smartlist_get(lines, 0);
smartlist_del_keeporder(lines, 0);
+ tor_free(item);
+ }
+
tt_assert(strstr(smartlist_get(lines, 0), "Say, this isn't too cool"));
- /* Next line is blank. */
- tt_assert(!strcmpstart(smartlist_get(lines, 1), "=============="));
- tt_assert(!strcmpstart(smartlist_get(lines, 2), "Minimal."));
- /* Next line is blank. */
- tt_assert(!strcmpstart(smartlist_get(lines, 3), "=============="));
- tt_str_op(smartlist_get(lines, 4), OP_EQ,
+ tt_str_op(smartlist_get(lines, 1), OP_EQ, "");
+ tt_assert(!strcmpstart(smartlist_get(lines, 2), "=============="));
+ tt_assert(!strcmpstart(smartlist_get(lines, 3), "Minimal."));
+ tt_str_op(smartlist_get(lines, 4), OP_EQ, "");
+ tt_assert(!strcmpstart(smartlist_get(lines, 5), "=============="));
+ tt_str_op(smartlist_get(lines, 6), OP_EQ,
"Testing any attempt to manually log from a signal.");
done:
tor_free(content);
+ SMARTLIST_FOREACH(lines, char *, x, tor_free(x));
smartlist_free(lines);
}
@@ -156,6 +160,7 @@ test_ratelim(void *arg)
tor_free(msg);
int i;
+ time_t first_suppressed_at = now + 60;
for (i = 0; i < 9; ++i) {
now += 60; /* one minute has passed. */
msg = rate_limit_log(&ten_min, now);
@@ -163,12 +168,15 @@ test_ratelim(void *arg)
tt_int_op(ten_min.last_allowed, OP_EQ, start);
tt_int_op(ten_min.n_calls_since_last_time, OP_EQ, i + 1);
}
+ tt_i64_op(ten_min.started_limiting, OP_EQ, first_suppressed_at);
now += 240; /* Okay, we can be done. */
msg = rate_limit_log(&ten_min, now);
tt_ptr_op(msg, OP_NE, NULL);
tt_str_op(msg, OP_EQ,
- " [9 similar message(s) suppressed in last 600 seconds]");
+ " [9 similar message(s) suppressed in last 720 seconds]");
+ tt_i64_op(now, OP_EQ, first_suppressed_at + 720);
+
done:
tor_free(msg);
}
diff --git a/src/test/test_mainloop.c b/src/test/test_mainloop.c
index 089ea812cf..c4e60d9da5 100644
--- a/src/test/test_mainloop.c
+++ b/src/test/test_mainloop.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,11 +6,29 @@
* \brief Tests for functions closely related to the Tor main loop
*/
+#define CONFIG_PRIVATE
+#define MAINLOOP_PRIVATE
+#define STATEFILE_PRIVATE
+
#include "test/test.h"
#include "test/log_test_helpers.h"
+#include "lib/confmgt/confmgt.h"
+
#include "core/or/or.h"
+#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
+#include "core/mainloop/mainloop_state_st.h"
+#include "core/mainloop/mainloop_sys.h"
+#include "core/mainloop/netstatus.h"
+
+#include "feature/hs/hs_service.h"
+
+#include "app/config/config.h"
+#include "app/config/statefile.h"
+#include "app/config/or_state_st.h"
+
+#include "app/main/subsysmgr.h"
static const uint64_t BILLION = 1000000000;
@@ -131,12 +149,233 @@ test_mainloop_update_time_jumps(void *arg)
monotime_disable_test_mocking();
}
+static int schedule_rescan_called = 0;
+static void
+mock_schedule_rescan_periodic_events(void)
+{
+ ++schedule_rescan_called;
+}
+
+static void
+test_mainloop_user_activity(void *arg)
+{
+ (void)arg;
+ const time_t start = 1542658829;
+ update_approx_time(start);
+
+ MOCK(schedule_rescan_periodic_events, mock_schedule_rescan_periodic_events);
+
+ reset_user_activity(start);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
+
+ set_network_participation(false);
+
+ // reset can move backwards and forwards, but does not change network
+ // participation.
+ reset_user_activity(start-10);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start-10);
+ reset_user_activity(start+10);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+10);
+
+ tt_int_op(schedule_rescan_called, OP_EQ, 0);
+ tt_int_op(false, OP_EQ, is_participating_on_network());
+
+ // "note" can only move forward. Calling it from a non-participating
+ // state makes us rescan the periodic callbacks and set participation.
+ note_user_activity(start+20);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+20);
+ tt_int_op(true, OP_EQ, is_participating_on_network());
+ tt_int_op(schedule_rescan_called, OP_EQ, 1);
+
+ // Calling it again will move us forward, but not call rescan again.
+ note_user_activity(start+25);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+25);
+ tt_int_op(true, OP_EQ, is_participating_on_network());
+ tt_int_op(schedule_rescan_called, OP_EQ, 1);
+
+ // We won't move backwards.
+ note_user_activity(start+20);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+25);
+ tt_int_op(true, OP_EQ, is_participating_on_network());
+ tt_int_op(schedule_rescan_called, OP_EQ, 1);
+
+ // We _will_ adjust if the clock jumps though.
+ netstatus_note_clock_jumped(500);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+525);
+
+ netstatus_note_clock_jumped(-400);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+125);
+
+ done:
+ UNMOCK(schedule_rescan_periodic_events);
+}
+
+static unsigned int
+mock_get_num_services(void)
+{
+ return 1;
+}
+
+static connection_t *
+mock_connection_gbtu(int type)
+{
+ (void) type;
+ return (void *)"hello fellow connections";
+}
+
+static void
+test_mainloop_check_participation(void *arg)
+{
+ (void)arg;
+ or_options_t *options = options_new();
+ const time_t start = 1542658829;
+ const time_t ONE_DAY = 24*60*60;
+
+ // Suppose we've been idle for a day or two
+ reset_user_activity(start - 2*ONE_DAY);
+ set_network_participation(true);
+ check_network_participation_callback(start, options);
+ tt_int_op(is_participating_on_network(), OP_EQ, false);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
+
+ // suppose we've been idle for 2 days... but we are a server.
+ reset_user_activity(start - 2*ONE_DAY);
+ options->ORPort_set = 1;
+ set_network_participation(true);
+ check_network_participation_callback(start+2, options);
+ tt_int_op(is_participating_on_network(), OP_EQ, true);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+2);
+ options->ORPort_set = 0;
+
+ // idle for 2 days, but we have a hidden service.
+ reset_user_activity(start - 2*ONE_DAY);
+ set_network_participation(true);
+ MOCK(hs_service_get_num_services, mock_get_num_services);
+ check_network_participation_callback(start+3, options);
+ tt_int_op(is_participating_on_network(), OP_EQ, true);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+3);
+ UNMOCK(hs_service_get_num_services);
+
+ // idle for 2 days but we have at least one user connection
+ MOCK(connection_get_by_type_nonlinked, mock_connection_gbtu);
+ reset_user_activity(start - 2*ONE_DAY);
+ set_network_participation(true);
+ options->DormantTimeoutDisabledByIdleStreams = 1;
+ check_network_participation_callback(start+10, options);
+ tt_int_op(is_participating_on_network(), OP_EQ, true);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start+10);
+
+ // as above, but DormantTimeoutDisabledByIdleStreams is not set
+ reset_user_activity(start - 2*ONE_DAY);
+ set_network_participation(true);
+ options->DormantTimeoutDisabledByIdleStreams = 0;
+ check_network_participation_callback(start+13, options);
+ tt_int_op(is_participating_on_network(), OP_EQ, false);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
+ UNMOCK(connection_get_by_type_nonlinked);
+ options->DormantTimeoutDisabledByIdleStreams = 1;
+
+ // idle for 2 days but DormantClientTimeout is 3 days
+ reset_user_activity(start - 2*ONE_DAY);
+ set_network_participation(true);
+ options->DormantClientTimeout = ONE_DAY * 3;
+ check_network_participation_callback(start+30, options);
+ tt_int_op(is_participating_on_network(), OP_EQ, true);
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
+
+ done:
+ or_options_free(options);
+ UNMOCK(hs_service_get_num_services);
+ UNMOCK(connection_get_by_type_nonlinked);
+}
+
+static void
+test_mainloop_dormant_load_state(void *arg)
+{
+ (void)arg;
+ or_state_t *or_state = or_state_new();
+ mainloop_state_t *state;
+ {
+ int idx = subsystems_get_state_idx(&sys_mainloop);
+ tor_assert(idx >= 0);
+ state = config_mgr_get_obj_mutable(get_state_mgr(), or_state, idx);
+ }
+ const time_t start = 1543956575;
+
+ reset_user_activity(0);
+ set_network_participation(false);
+
+ // When we construct a new state, it starts out in "auto" mode.
+ tt_int_op(state->Dormant, OP_EQ, -1);
+
+ // Initializing from "auto" makes us start out (by default) non-Dormant,
+ // with activity right now.
+ netstatus_load_from_state(state, start);
+ tt_assert(is_participating_on_network());
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
+
+ // Initializing from dormant clears the last user activity time, and
+ // makes us dormant.
+ state->Dormant = 1;
+ netstatus_load_from_state(state, start);
+ tt_assert(! is_participating_on_network());
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, 0);
+
+ // Initializing from non-dormant sets the last user activity time, and
+ // makes us non-dormant.
+ state->Dormant = 0;
+ state->MinutesSinceUserActivity = 123;
+ netstatus_load_from_state(state, start);
+ tt_assert(is_participating_on_network());
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start - 123*60);
+
+ // If we would start dormant, but DormantCanceledByStartup is set, then
+ // we start up non-dormant.
+ state->Dormant = 1;
+ get_options_mutable()->DormantCanceledByStartup = 1;
+ netstatus_load_from_state(state, start);
+ tt_assert(is_participating_on_network());
+ tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
+
+ done:
+ or_state_free(or_state);
+}
+
+static void
+test_mainloop_dormant_save_state(void *arg)
+{
+ (void)arg;
+ mainloop_state_t *state = tor_malloc_zero(sizeof(mainloop_state_t));
+ const time_t start = 1543956575;
+
+ // Can we save a non-dormant state correctly?
+ reset_user_activity(start - 1000);
+ set_network_participation(true);
+ netstatus_flush_to_state(state, start);
+
+ tt_int_op(state->Dormant, OP_EQ, 0);
+ tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 1000 / 60);
+
+ // Can we save a dormant state correctly?
+ set_network_participation(false);
+ netstatus_flush_to_state(state, start);
+
+ tt_int_op(state->Dormant, OP_EQ, 1);
+ tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 0);
+
+ done:
+ tor_free(state);
+}
+
#define MAINLOOP_TEST(name) \
{ #name, test_mainloop_## name , TT_FORK, NULL, NULL }
struct testcase_t mainloop_tests[] = {
MAINLOOP_TEST(update_time_normal),
MAINLOOP_TEST(update_time_jumps),
+ MAINLOOP_TEST(user_activity),
+ MAINLOOP_TEST(check_participation),
+ MAINLOOP_TEST(dormant_load_state),
+ MAINLOOP_TEST(dormant_save_state),
END_OF_TESTCASES
};
-
diff --git a/src/test/test_metrics.c b/src/test/test_metrics.c
new file mode 100644
index 0000000000..58628e8483
--- /dev/null
+++ b/src/test/test_metrics.c
@@ -0,0 +1,277 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_metrics.c
+ * \brief Test lib/metrics and feature/metrics functionalities
+ */
+
+#define CONFIG_PRIVATE
+#define CONNECTION_PRIVATE
+#define MAINLOOP_PRIVATE
+#define METRICS_STORE_ENTRY_PRIVATE
+
+#include "test/test.h"
+#include "test/test_helpers.h"
+#include "test/log_test_helpers.h"
+
+#include "app/config/config.h"
+
+#include "core/mainloop/connection.h"
+#include "core/mainloop/mainloop.h"
+#include "core/or/connection_st.h"
+#include "core/or/policies.h"
+#include "core/or/port_cfg_st.h"
+
+#include "feature/metrics/metrics.h"
+
+#include "lib/encoding/confline.h"
+#include "lib/metrics/metrics_store.h"
+
+#define TEST_METRICS_ENTRY_NAME "entryA"
+#define TEST_METRICS_ENTRY_HELP "Description of entryA"
+#define TEST_METRICS_ENTRY_LABEL_1 "label=\"farfadet\""
+#define TEST_METRICS_ENTRY_LABEL_2 "label=\"ponki\""
+
+static void
+set_metrics_port(or_options_t *options)
+{
+ const char *port = "MetricsPort 9035"; /* Default to 127.0.0.1 */
+ const char *policy = "MetricsPortPolicy accept 1.2.3.4";
+
+ config_get_lines(port, &options->MetricsPort_lines, 0);
+ config_get_lines(policy, &options->MetricsPortPolicy, 0);
+
+ /* Parse and validate policy. */
+ policies_parse_from_options(options);
+}
+
+static void
+test_config(void *arg)
+{
+ char *err_msg = NULL;
+ tor_addr_t addr;
+ smartlist_t *ports = smartlist_new();
+ or_options_t *options = get_options_mutable();
+
+ (void) arg;
+
+ set_metrics_port(options);
+
+ int ret = metrics_parse_ports(options, ports, &err_msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(smartlist_len(ports), OP_EQ, 1);
+
+ /* Validate the configured port. */
+ const port_cfg_t *cfg = smartlist_get(ports, 0);
+ tt_assert(tor_addr_eq_ipv4h(&cfg->addr, 0x7f000001));
+ tt_int_op(cfg->port, OP_EQ, 9035);
+ tt_int_op(cfg->type, OP_EQ, CONN_TYPE_METRICS_LISTENER);
+
+ /* Address of the policy should be permitted. */
+ tor_addr_from_ipv4h(&addr, 0x01020304); /* 1.2.3.4 */
+ ret = metrics_policy_permits_address(&addr);
+ tt_int_op(ret, OP_EQ, true);
+
+ /* Anything else, should not. */
+ tor_addr_from_ipv4h(&addr, 0x01020305); /* 1.2.3.5 */
+ ret = metrics_policy_permits_address(&addr);
+ tt_int_op(ret, OP_EQ, false);
+
+ done:
+ SMARTLIST_FOREACH(ports, port_cfg_t *, c, port_cfg_free(c));
+ smartlist_free(ports);
+ or_options_free(options);
+ tor_free(err_msg);
+}
+
+static char _c_buf[256];
+#define CONTAINS(conn, msg) \
+ do { \
+ tt_int_op(buf_datalen(conn->outbuf), OP_EQ, (strlen(msg))); \
+ memset(_c_buf, 0, sizeof(_c_buf)); \
+ buf_get_bytes(conn->outbuf, _c_buf, (strlen(msg))); \
+ tt_str_op(_c_buf, OP_EQ, (msg)); \
+ tt_int_op(buf_datalen(conn->outbuf), OP_EQ, 0); \
+ } while (0)
+
+#define WRITE(conn, msg) \
+ buf_add(conn->inbuf, (msg), (strlen(msg)));
+
+/* Free the previous conn object if any and allocate a new connection. In
+ * order to be allowed, set its address to 1.2.3.4 as per the policy. */
+#define NEW_ALLOWED_CONN() \
+ do { \
+ close_closeable_connections(); \
+ conn = connection_new(CONN_TYPE_METRICS, AF_INET); \
+ tor_addr_from_ipv4h(&conn->addr, 0x01020304); \
+ } while (0)
+
+static void
+test_connection(void *arg)
+{
+ int ret;
+ connection_t *conn = NULL;
+ or_options_t *options = get_options_mutable();
+
+ (void) arg;
+
+ /* Notice that in this test, we will allocate a new connection at every test
+ * case. This is because the metrics_connection_process_inbuf() marks for
+ * close the connection in case of an error and thus we can't call again an
+ * inbuf process function on a marked for close connection. */
+
+ tor_init_connection_lists();
+
+ /* Setup policy. */
+ set_metrics_port(options);
+
+ /* Set 1.2.3.5 IP, we should get rejected. */
+ NEW_ALLOWED_CONN();
+ tor_addr_from_ipv4h(&conn->addr, 0x01020305);
+ ret = metrics_connection_process_inbuf(conn);
+ tt_int_op(ret, OP_EQ, -1);
+
+ /* No HTTP request yet. */
+ NEW_ALLOWED_CONN();
+ ret = metrics_connection_process_inbuf(conn);
+ tt_int_op(ret, OP_EQ, 0);
+ connection_free_minimal(conn);
+
+ /* Bad request. */
+ NEW_ALLOWED_CONN();
+ WRITE(conn, "HTTP 4.7\r\n\r\n");
+ ret = metrics_connection_process_inbuf(conn);
+ tt_int_op(ret, OP_EQ, -1);
+ CONTAINS(conn, "HTTP/1.0 400 Bad Request\r\n\r\n");
+
+ /* Path not found. */
+ NEW_ALLOWED_CONN();
+ WRITE(conn, "GET /badpath HTTP/1.0\r\n\r\n");
+ ret = metrics_connection_process_inbuf(conn);
+ tt_int_op(ret, OP_EQ, -1);
+ CONTAINS(conn, "HTTP/1.0 404 Not Found\r\n\r\n");
+
+ /* Method not allowed. */
+ NEW_ALLOWED_CONN();
+ WRITE(conn, "POST /something HTTP/1.0\r\n\r\n");
+ ret = metrics_connection_process_inbuf(conn);
+ tt_int_op(ret, OP_EQ, -1);
+ CONTAINS(conn, "HTTP/1.0 405 Method Not Allowed\r\n\r\n");
+
+ /* Ask for metrics. The content should be above 0. We don't test the
+ * validity of the returned content but it is certainly not an error. */
+ NEW_ALLOWED_CONN();
+ WRITE(conn, "GET /metrics HTTP/1.0\r\n\r\n");
+ ret = metrics_connection_process_inbuf(conn);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(buf_datalen(conn->outbuf), OP_GT, 0);
+
+ done:
+ or_options_free(options);
+ connection_free_minimal(conn);
+}
+
+static void
+test_prometheus(void *arg)
+{
+ metrics_store_t *store = NULL;
+ metrics_store_entry_t *entry = NULL;
+ buf_t *buf = buf_new();
+ char *output = NULL;
+
+ (void) arg;
+
+ /* Fresh new store. No entries. */
+ store = metrics_store_new();
+ tt_assert(store);
+
+ /* Add entry and validate its content. */
+ entry = metrics_store_add(store, METRICS_TYPE_COUNTER,
+ TEST_METRICS_ENTRY_NAME,
+ TEST_METRICS_ENTRY_HELP);
+ tt_assert(entry);
+ metrics_store_entry_add_label(entry, TEST_METRICS_ENTRY_LABEL_1);
+
+ static const char *expected =
+ "# HELP " TEST_METRICS_ENTRY_NAME " " TEST_METRICS_ENTRY_HELP "\n"
+ "# TYPE " TEST_METRICS_ENTRY_NAME " counter\n"
+ TEST_METRICS_ENTRY_NAME "{" TEST_METRICS_ENTRY_LABEL_1 "} 0\n";
+
+ metrics_store_get_output(METRICS_FORMAT_PROMETHEUS, store, buf);
+ output = buf_extract(buf, NULL);
+ tt_str_op(expected, OP_EQ, output);
+
+ done:
+ buf_free(buf);
+ tor_free(output);
+ metrics_store_free(store);
+}
+
+static void
+test_store(void *arg)
+{
+ metrics_store_t *store = NULL;
+ metrics_store_entry_t *entry = NULL;
+
+ (void) arg;
+
+ /* Fresh new store. No entries. */
+ store = metrics_store_new();
+ tt_assert(store);
+ tt_assert(!metrics_store_get_all(store, TEST_METRICS_ENTRY_NAME));
+
+ /* Add entry and validate its content. */
+ entry = metrics_store_add(store, METRICS_TYPE_COUNTER,
+ TEST_METRICS_ENTRY_NAME,
+ TEST_METRICS_ENTRY_HELP);
+ tt_assert(entry);
+ tt_int_op(entry->type, OP_EQ, METRICS_TYPE_COUNTER);
+ tt_str_op(entry->name, OP_EQ, TEST_METRICS_ENTRY_NAME);
+ tt_str_op(entry->help, OP_EQ, TEST_METRICS_ENTRY_HELP);
+ tt_uint_op(entry->u.counter.value, OP_EQ, 0);
+
+ /* Access the entry. */
+ tt_assert(metrics_store_get_all(store, TEST_METRICS_ENTRY_NAME));
+
+ /* Add a label to the entry to make it unique. */
+ metrics_store_entry_add_label(entry, TEST_METRICS_ENTRY_LABEL_1);
+ tt_int_op(metrics_store_entry_has_label(entry, TEST_METRICS_ENTRY_LABEL_1),
+ OP_EQ, true);
+
+ /* Update entry's value. */
+ metrics_store_entry_update(entry, 42);
+ tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 42);
+ metrics_store_entry_update(entry, 42);
+ tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 84);
+ metrics_store_entry_reset(entry);
+ tt_int_op(metrics_store_entry_get_value(entry), OP_EQ, 0);
+
+ /* Add a new entry of same name but different label. */
+ /* Add entry and validate its content. */
+ entry = metrics_store_add(store, METRICS_TYPE_COUNTER,
+ TEST_METRICS_ENTRY_NAME,
+ TEST_METRICS_ENTRY_HELP);
+ tt_assert(entry);
+ metrics_store_entry_add_label(entry, TEST_METRICS_ENTRY_LABEL_2);
+
+ /* Make sure _both_ entries are there. */
+ const smartlist_t *entries =
+ metrics_store_get_all(store, TEST_METRICS_ENTRY_NAME);
+ tt_assert(entries);
+ tt_int_op(smartlist_len(entries), OP_EQ, 2);
+
+ done:
+ metrics_store_free(store);
+}
+
+struct testcase_t metrics_tests[] = {
+
+ { "config", test_config, TT_FORK, NULL, NULL },
+ { "connection", test_connection, TT_FORK, NULL, NULL },
+ { "prometheus", test_prometheus, TT_FORK, NULL, NULL },
+ { "store", test_store, TT_FORK, NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index 4c4317d81a..6bd1f56859 100644
--- a/src/test/test_microdesc.c
+++ b/src/test/test_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -11,6 +11,7 @@
#include "feature/dirparse/routerparse.h"
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/nodefamily.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/torcert.h"
@@ -20,6 +21,7 @@
#include "feature/nodelist/routerstatus_st.h"
#include "test/test.h"
+#include "test/log_test_helpers.h"
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
@@ -38,7 +40,8 @@ static const char test_md1[] =
"MIGJAoGBAMjlHH/daN43cSVRaHBwgUfnszzAhg98EvivJ9Qxfv51mvQUxPjQ07es\n"
"gV/3n8fyh3Kqr/ehi9jxkdgSRfSnmF7giaHL1SLZ29kA7KtST+pBvmTpDtHa3ykX\n"
"Xorc7hJvIyTZoc1HU+5XSynj3gsBE5IGK1ZRzrNS688LnuZMVp1tAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n";
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n";
static const char test_md2[] =
"onion-key\n"
@@ -46,7 +49,8 @@ static const char test_md2[] =
"MIGJAoGBAMIixIowh2DyPmDNMDwBX2DHcYcqdcH1zdIQJZkyV6c6rQHnvbcaDoSg\n"
"jgFSLJKpnGmh71FVRqep+yVB0zI1JY43kuEnXry2HbZCD9UDo3d3n7t015X5S7ON\n"
"bSSYtQGPwOr6Epf96IF6DoQxy4iDnPUAlejuhAG51s1y6/rZQ3zxAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n";
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n";
static const char test_md3[] =
"@last-listed 2009-06-22\n"
@@ -56,6 +60,7 @@ static const char test_md3[] =
"qj2fRZzfxlc88G/tmiaHshmdtEpklZ740OFqaaJVj4LjPMKFNE+J7Xc1142BE9Ci\n"
"KgsbjGYe2RY261aADRWLetJ8T9QDMm+JngL4288hc8pq1uB/3TAbAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
"p accept 1-700,800-1000\n"
"family nodeX nodeY nodeZ\n";
@@ -70,6 +75,7 @@ test_md_cache(void *data)
const char *test_md3_noannotation = strchr(test_md3, '\n')+1;
time_t time1, time2, time3;
char *fn = NULL, *s = NULL;
+ char *encoded_family = NULL;
(void)data;
options = get_options_mutable();
@@ -172,8 +178,9 @@ test_md_cache(void *data)
tt_ptr_op(md1->family, OP_EQ, NULL);
tt_ptr_op(md3->family, OP_NE, NULL);
- tt_int_op(smartlist_len(md3->family), OP_EQ, 3);
- tt_str_op(smartlist_get(md3->family, 0), OP_EQ, "nodeX");
+
+ encoded_family = nodefamily_format(md3->family);
+ tt_str_op(encoded_family, OP_EQ, "nodex nodey nodez");
/* Now rebuild the cache! */
tt_int_op(microdesc_cache_rebuild(mc, 1), OP_EQ, 0);
@@ -254,6 +261,7 @@ test_md_cache(void *data)
smartlist_free(wanted);
tor_free(s);
tor_free(fn);
+ tor_free(encoded_family);
}
static const char truncated_md[] =
@@ -304,118 +312,94 @@ test_md_cache_broken(void *data)
/* Generated by chutney. */
static const char test_ri[] =
"router test005r 127.0.0.1 5005 0 7005\n"
- "platform Tor 0.2.5.4-alpha-dev on Linux\n"
- "protocols Link 1 2 Circuit 1\n"
- "published 2014-05-06 22:57:55\n"
- "fingerprint 09DE 3BA2 48C2 1C3F 3760 6CD3 8460 43A6 D5EC F59E\n"
- "uptime 0\n"
- "bandwidth 1073741824 1073741824 0\n"
- "extra-info-digest 361F9428F9FA4DD854C03DDBCC159D0D9FA996C9\n"
- "onion-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANBJz8Vldl12aFeSMPLiA4nOetLDN0oxU8bB1SDhO7Uu2zdWYVYAF5J0\n"
- "st7WvrVy/jA9v/fsezNAPskBanecHRSkdMTpkcgRPMHE7CTGEwIy1Yp1X4bPgDlC\n"
- "VCnbs5Pcts5HnWEYNK7qHDAUn+IlmjOO+pTUY8uyq+GQVz6H9wFlAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "signing-key\n"
- "-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANbGUC4802Ke6C3nOVxN0U0HhIRrs32cQFEL4v+UUMJPgjbistHBvOax\n"
- "CWVR/sMXM2kKJeGThJ9ZUs2p9dDG4WHPUXgkMqzTTEeeFa7pQKU0brgbmLaJq0Pi\n"
- "mxmqC5RkTHa5bQvq6QlSFprAEoovV27cWqBM9jVdV9hyc//6kwPzAgMBAAE=\n"
- "-----END RSA PUBLIC KEY-----\n"
- "hidden-service-dir\n"
- "ntor-onion-key Gg73xH7+kTfT6bi1uNVx9gwQdQas9pROIfmc4NpAdC4=\n"
- "reject *:25\n"
- "reject *:119\n"
- "reject *:135-139\n"
- "reject *:445\n"
- "reject *:563\n"
- "reject *:1214\n"
- "reject *:4661-4666\n"
- "reject *:6346-6429\n"
- "reject *:6699\n"
- "reject *:6881-6999\n"
- "accept *:*\n"
- "router-signature\n"
- "-----BEGIN SIGNATURE-----\n"
- "ImzX5PF2vRCrG1YzGToyjoxYhgh1vtHEDjmP+tIS/iil1DSnHZNpHSuHp0L1jE9S\n"
- "yZyrtKaqpBE/aecAM3j4CWCn/ipnAAQkHcyRLin1bYvqBtRzyopVCRlUhF+uWrLq\n"
- "t0xkIE39ss/EwmQr7iIgkdVH4oRIMsjYnFFJBG26nYY=\n"
- "-----END SIGNATURE-----\n";
-
-static const char test_ri2[] =
- "router test001a 127.0.0.1 5001 0 7001\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQQABf/FAf5iDuKCZP2VxnAaQWdklilAh6kaEeFX4z8261Yx2T1/AQAgBADCp8vO\n"
- "B8K1F9g2DzwuwvVCnPFLSK1qknVqPpNucHLH9DY7fuIYogBAdz4zHv1qC7RKaMNG\n"
- "Jux/tMO2tzPcm62Ky5PjClMQplKUOnZNQ+RIpA3wYCIfUDy/cQnY7XWgNQ0=\n"
+ "AQQABs1eAfTuBhu6ypB5/9avDiY3qBzulkCvfYqbFN/ABk/o4xFcAQAgBAAnmWRG\n"
+ "rIvqpb4Kk3cThEiWAll4uDCO2Y46uNm9WG7AtPt4LG+XfktG3GAxv6aVQimwlyHc\n"
+ "1x2Lfm9KG3mWWj+hxnum4Z7873OE0B9l2Hg0YQZCW/PuHSWN0rspTvY5SgA=\n"
"-----END ED25519 CERT-----\n"
- "platform Tor 0.2.6.0-alpha-dev on Darwin\n"
- "protocols Link 1 2 Circuit 1\n"
- "published 2014-10-08 12:58:04\n"
- "fingerprint B7E2 7F10 4213 C36F 13E7 E982 9182 845E 4959 97A0\n"
- "uptime 0\n"
- "bandwidth 1073741824 1073741824 0\n"
- "extra-info-digest 568F27331B6D8C73E7024F1EF5D097B90DFC7CDB\n"
- "caches-extra-info\n"
+ "master-key-ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n"
+ "or-address [::]:5005\n"
+ "platform Tor 0.4.5.0-alpha-dev on Linux\n"
+ "proto Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 "
+ "HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-3\n"
+ "published 2020-10-13 13:27:34\n"
+ "fingerprint D219 590A C951 3BCD EBBA 9AB7 2100 7A4C C01B BAE3\n"
+ "uptime 324451\n"
+ "bandwidth 1073741824 1073741824 637796\n"
+ "extra-info-digest 78E6D382BC826B95B4111554EEE7D541A32AAAA3 "
+ "c61Onjpq+1S0TrdvoaOvGAxew6yfO+uHNhipbemQmgA\n"
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAL2R8EfubUcahxha4u02P4VAR0llQIMwFAmrHPjzcK7apcQgDOf2ovOA\n"
- "+YQnJFxlpBmCoCZC6ssCi+9G0mqo650lFuTMP5I90BdtjotfzESfTykHLiChyvhd\n"
- "l0dlqclb2SU/GKem/fLRXH16aNi72CdSUu/1slKs/70ILi34QixRAgMBAAE=\n"
+ "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n"
+ "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n"
+ "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
"signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAN8+78KUVlgHXdMMkYJxcwh1Zv2y+Gb5eWUyltUaQRajhrT9ij2T5JZs\n"
- "M0g85xTcuM3jNVVpV79+33hiTohdC6UZ+Bk4USQ7WBFzRbVFSXoVKLBJFkCOIexg\n"
- "SMGNd5WEDtHWrXl58mizmPFu1eG6ZxHzt7RuLSol5cwBvawXPNkFAgMBAAE=\n"
+ "MIGJAoGBANBzejGAwyPTPq2Gm03wpg3qICo0uDQau8opude2mW3eyxAqOqHzC8De\n"
+ "gRgbmn040vqe9gwvH4iaHpVeTxyDwQefbfULdq6bETmX3aSUj6LKBCqqcyuOJFQu\n"
+ "7M2QfNSfHtldUABpIaqFvEA3AV8qjOoUtauoFNJKMy7Wj2//S70VAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
"onion-key-crosscert\n"
"-----BEGIN CROSSCERT-----\n"
- "ETFDzU49bvNfoZnKK1j6JeBP2gDirgj6bBCgWpUYs663OO9ypbZRO0JwWANssKl6\n"
- "oaq9vKTsKGRsaNnqnz/JGMhehymakjjNtqg7crWwsahe8+7Pw9GKmW+YjFtcOkUf\n"
- "KfOn2bmKBa1FoJb4yW3oXzHcdlLSRuCciKqPn+Hky5o=\n"
+ "pD3Nkkunt8zP6PO6H3uHT0t7xnorC7cY/KfF75mFB+90pHCD9f0Xdu3Pjrur/q23\n"
+ "PIKV3hdtdsODoJuoh8LPGNAjS5rO6HMCtHNDNunNOs69bvfaO0jThnurXmOpY0sW\n"
+ "eRfBeYN2KNgrN0B1eDejfPSr03dkFY48yoUDROv9EJQ=\n"
"-----END CROSSCERT-----\n"
"ntor-onion-key-crosscert 0\n"
"-----BEGIN ED25519 CERT-----\n"
- "AQoABf2dAcKny84HwrUX2DYPPC7C9UKc8UtIrWqSdWo+k25wcsf0AFohutG+xI06\n"
- "Ef21c5Zl1j8Hw6DzHDjYyJevXLFuOneaL3zcH2Ldn4sjrG3kc5UuVvRfTvV120UO\n"
- "xk4f5s5LGwY=\n"
+ "AQoABs2OASeZZEasi+qlvgqTdxOESJYCWXi4MI7Zjjq42b1YbsC0AKc5y5qYUYvw\n"
+ "VATtWkV9DVIZbZSb9mQP5pmNaqmX+DbmINCYt8j7l+U7g3ftUyh0Wlrgevx0pFUI\n"
+ "RcIU0HKHZQA=\n"
"-----END ED25519 CERT-----\n"
"hidden-service-dir\n"
- "contact auth1@test.test\n"
- "ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n"
- "reject *:*\n"
- "router-sig-ed25519 5aQXyTif7PExIuL2di37UvktmJECKnils2OWz2vDi"
- "hFxi+5TTAAPxYkS5clhc/Pjvw34itfjGmTKFic/8httAQ\n"
+ "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA\n"
+ "accept *:*\n"
+ "tunnelled-dir-server\n"
+ "router-sig-ed25519 Xm56dYbo/hCHWyzcdUPmfTeZ4qly2TYf1/2Q1lXKQDMJyBti"
+ "8ZE8R2TTYsYimr+UtAapbzBItccZLze505nhBw\n"
"router-signature\n"
"-----BEGIN SIGNATURE-----\n"
- "BaUB+aFPQbb3BwtdzKsKqV3+6cRlSqJF5bI3UTmwRoJk+Z5Pz+W5NWokNI0xArHM\n"
- "T4T5FZCCP9350jXsUCIvzyIyktU6aVRCGFt76rFlo1OETpN8GWkMnQU0w18cxvgS\n"
- "cf34GXHv61XReJF3AlzNHFpbrPOYmowmhrTULKyMqow=\n"
+ "bbeN0lq6nCfJQXGcKa1M9TQ6b2upig7clrlVXuzKeR0JhGwnDCXUAFxDtrw3vkVo\n"
+ "ExBXXvJeBPyustFOQkdiAEWHHSW5CwEgeVCBYZeEnaiySIgDVKuu+9B53ezFdC0Y\n"
+ "iFJkKxxDx7ksxX0zdl7aPT4ORFEuRhCYS6el7YJmoyg=\n"
"-----END SIGNATURE-----\n";
-static const char test_md_18[] =
+static const char test_md2_25[] =
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBANBJz8Vldl12aFeSMPLiA4nOetLDN0oxU8bB1SDhO7Uu2zdWYVYAF5J0\n"
- "st7WvrVy/jA9v/fsezNAPskBanecHRSkdMTpkcgRPMHE7CTGEwIy1Yp1X4bPgDlC\n"
- "VCnbs5Pcts5HnWEYNK7qHDAUn+IlmjOO+pTUY8uyq+GQVz6H9wFlAgMBAAE=\n"
+ "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n"
+ "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n"
+ "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key Gg73xH7+kTfT6bi1uNVx9gwQdQas9pROIfmc4NpAdC4=\n"
- "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n"
- "id rsa1024 Cd47okjCHD83YGzThGBDptXs9Z4\n";
+ "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA=\n"
+ "p accept 1-65535\n"
+ "id ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n";
+
+static const char test_md2_withfamily_28[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n"
+ "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n"
+ "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA=\n"
+ "family OtherNode !Strange\n"
+ "p accept 1-65535\n"
+ "id ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n";
-static const char test_md2_21[] =
+static const char test_md2_withfamily_29[] =
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
- "MIGJAoGBAL2R8EfubUcahxha4u02P4VAR0llQIMwFAmrHPjzcK7apcQgDOf2ovOA\n"
- "+YQnJFxlpBmCoCZC6ssCi+9G0mqo650lFuTMP5I90BdtjotfzESfTykHLiChyvhd\n"
- "l0dlqclb2SU/GKem/fLRXH16aNi72CdSUu/1slKs/70ILi34QixRAgMBAAE=\n"
+ "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n"
+ "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n"
+ "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
- "ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n"
- "id ed25519 wqfLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx/Q\n";
+ "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA=\n"
+ "family !Strange $D219590AC9513BCDEBBA9AB721007A4CC01BBAE3 othernode\n"
+ "p accept 1-65535\n"
+ "id ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n";
static void
test_md_generate(void *arg)
@@ -427,25 +411,21 @@ test_md_generate(void *arg)
ri = router_parse_entry_from_string(test_ri, NULL, 0, 0, NULL, NULL);
tt_assert(ri);
- microdesc_free(md);
- md = NULL;
- md = dirvote_create_microdescriptor(ri, 18);
- tt_str_op(md->body, OP_EQ, test_md_18);
+ md = dirvote_create_microdescriptor(ri, 25);
+ tt_str_op(md->body, OP_EQ, test_md2_25);
+ tt_assert(ed25519_pubkey_eq(md->ed25519_identity_pkey,
+ &ri->cache_info.signing_key_cert->signing_key));
+ // Try family encoding.
microdesc_free(md);
- md = NULL;
- md = dirvote_create_microdescriptor(ri, 21);
- tt_str_op(md->body, OP_EQ, test_md_18);
-
- routerinfo_free(ri);
- ri = router_parse_entry_from_string(test_ri2, NULL, 0, 0, NULL, NULL);
+ ri->declared_family = smartlist_new();
+ smartlist_add_strdup(ri->declared_family, "OtherNode !Strange");
+ md = dirvote_create_microdescriptor(ri, 28);
+ tt_str_op(md->body, OP_EQ, test_md2_withfamily_28);
microdesc_free(md);
- md = NULL;
- md = dirvote_create_microdescriptor(ri, 21);
- tt_str_op(md->body, OP_EQ, test_md2_21);
- tt_assert(ed25519_pubkey_eq(md->ed25519_identity_pkey,
- &ri->cache_info.signing_key_cert->signing_key));
+ md = dirvote_create_microdescriptor(ri, 29);
+ tt_str_op(md->body, OP_EQ, test_md2_withfamily_29);
done:
microdesc_free(md);
@@ -453,7 +433,7 @@ test_md_generate(void *arg)
}
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-DISABLE_GCC_WARNING(overlength-strings)
+DISABLE_GCC_WARNING("-Woverlength-strings")
/* We allow huge string constants in the unit tests, but not in the code
* at large. */
#endif
@@ -467,6 +447,7 @@ static const char MD_PARSE_TEST_DATA[] =
"DBr/ij6+JqgVFeriuiMzHKREytzjdaTuKsKBFFpLwb+Ppcjr5nMIH/AR6/aHO8hW\n"
"T3B9lx5T6Kl7CqZ4yqXxYRHzn50EPTIZuz0y9se4J4gi9mLmL+pHAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
"p accept 20-23,43,53,79-81,88,110,143,194,220,443,464,531,543-544\n"
"id rsa1024 GEo59/iR1GWSIWZDzXTd5QxtqnU\n"
/* Bad 0: I've messed with the onion-key in the second one. */
@@ -526,6 +507,7 @@ static const char MD_PARSE_TEST_DATA[] =
"h8G5OJZHRarJQyCIf7vpZQAi0oP0OkGGaCaDQsM+D8TnqhnU++RWGnMqY/cXxPrL\n"
"MEq+n6aGiLmzkO7ah8yorZpoREk4GqLUIN89/tHHGOhJL3c4CPGjAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
"p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n"
"id rsa1234 jlqAKFD2E7uMKv+8TmKSeo7NBho\n"
/* Good 5: Extra id type. */
@@ -611,9 +593,44 @@ static const char MD_PARSE_TEST_DATA[] =
"ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
"id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
"p6 allow 80\n"
+ /* Good 11: Normal, non-exit relay with ipv6 address */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
+ "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
+ "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "a [::1:2:3:4]:9090\n"
+ "a 18.0.0.1:9999\n"
+ "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
+ "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
+ /* Good 12: Normal, exit relay with ipv6 address */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
+ "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
+ "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "a [::1:2:3:4]:9090\n"
+ "a 18.0.0.1:9999\n"
+ "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
+ "p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544\n"
+ "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
+ /* Good 13: Normal, exit relay with only ipv6 exit policy */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
+ "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
+ "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "a [::1:2:3:4]:9090\n"
+ "a 18.0.0.1:9999\n"
+ "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
+ "p6 accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544\n"
+ "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
;
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
-ENABLE_GCC_WARNING(overlength-strings)
+ENABLE_GCC_WARNING("-Woverlength-strings")
#endif
/** More tests for parsing different kinds of microdescriptors, and getting
@@ -628,7 +645,7 @@ test_md_parse(void *arg)
smartlist_t *mds = microdescs_parse_from_string(MD_PARSE_TEST_DATA,
NULL, 1, SAVED_NOWHERE,
invalid);
- tt_int_op(smartlist_len(mds), OP_EQ, 11);
+ tt_int_op(smartlist_len(mds), OP_EQ, 14);
tt_int_op(smartlist_len(invalid), OP_EQ, 4);
test_memeq_hex(smartlist_get(invalid,0),
@@ -675,6 +692,21 @@ test_md_parse(void *arg)
tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
tt_int_op(md->ipv6_orport, OP_EQ, 9090);
+ md = smartlist_get(mds, 11);
+ tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
+ tt_int_op(md->ipv6_orport, OP_EQ, 9090);
+ tt_int_op(md->policy_is_reject_star, OP_EQ, 1);
+
+ md = smartlist_get(mds, 12);
+ tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
+ tt_int_op(md->ipv6_orport, OP_EQ, 9090);
+ tt_int_op(md->policy_is_reject_star, OP_EQ, 0);
+
+ md = smartlist_get(mds, 13);
+ tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
+ tt_int_op(md->ipv6_orport, OP_EQ, 9090);
+ tt_int_op(md->policy_is_reject_star, OP_EQ, 0);
+
done:
SMARTLIST_FOREACH(mds, microdesc_t *, mdsc, microdesc_free(mdsc));
smartlist_free(mds);
@@ -683,6 +715,83 @@ test_md_parse(void *arg)
tor_free(mem_op_hex_tmp);
}
+static void
+test_md_parse_id_ed25519(void *arg)
+{
+ (void)arg;
+
+ /* A correct MD with an ed25519 ID ... and an unspecified ID type,
+ * which is permitted. */
+ const char GOOD_MD[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
+ "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
+ "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
+ "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n"
+ "id wumpus dodecahedron\n";
+
+ smartlist_t *mds = NULL;
+ const microdesc_t *md;
+
+ mds = microdescs_parse_from_string(GOOD_MD,
+ NULL, 1, SAVED_NOWHERE, NULL);
+ tt_assert(mds);
+ tt_int_op(smartlist_len(mds), OP_EQ, 1);
+ md = smartlist_get(mds, 0);
+ tt_mem_op(md->ed25519_identity_pkey, OP_EQ,
+ "This isn't actually a public key", ED25519_PUBKEY_LEN);
+ SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m));
+ smartlist_free(mds);
+
+ /* As above, but ed25519 ID key appears twice. */
+ const char DUPLICATE_KEY[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
+ "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
+ "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs\n"
+ "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n"
+ "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n";
+
+ setup_capture_of_logs(LOG_WARN);
+ mds = microdescs_parse_from_string(DUPLICATE_KEY,
+ NULL, 1, SAVED_NOWHERE, NULL);
+ tt_assert(mds);
+ tt_int_op(smartlist_len(mds), OP_EQ, 0); // no entries.
+ expect_single_log_msg_containing("Extra ed25519 key");
+ mock_clean_saved_logs();
+ smartlist_free(mds);
+
+ /* As above, but ed25519 ID key is invalid. */
+ const char BOGUS_KEY[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
+ "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
+ "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs\n"
+ "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyZZZZZZZZZZZ\n";
+
+ mds = microdescs_parse_from_string(BOGUS_KEY,
+ NULL, 1, SAVED_NOWHERE, NULL);
+ tt_assert(mds);
+ tt_int_op(smartlist_len(mds), OP_EQ, 0); // no entries.
+ expect_single_log_msg_containing("Bogus ed25519 key");
+
+ done:
+ if (mds) {
+ SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m));
+ smartlist_free(mds);
+ }
+ teardown_capture_of_logs();
+}
+
static int mock_rgsbd_called = 0;
static routerstatus_t *mock_rgsbd_val_a = NULL;
static routerstatus_t *mock_rgsbd_val_b = NULL;
@@ -816,6 +925,7 @@ struct testcase_t microdesc_tests[] = {
{ "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL },
{ "generate", test_md_generate, 0, NULL, NULL },
{ "parse", test_md_parse, 0, NULL, NULL },
+ { "parse_id_ed25519", test_md_parse_id_ed25519, 0, NULL, NULL },
{ "reject_cache", test_md_reject_cache, TT_FORK, NULL, NULL },
{ "corrupt_desc", test_md_corrupt_desc, TT_FORK, NULL, NULL },
END_OF_TESTCASES
diff --git a/src/test/test_namemap.c b/src/test/test_namemap.c
new file mode 100644
index 0000000000..e93d3fbc3c
--- /dev/null
+++ b/src/test/test_namemap.c
@@ -0,0 +1,174 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "test/test.h"
+
+#include "lib/cc/torint.h"
+#include "lib/container/namemap.h"
+#include "lib/container/namemap_st.h"
+#include "lib/malloc/malloc.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static void
+test_namemap_empty(void *arg)
+{
+ (void)arg;
+
+ namemap_t m;
+ namemap_init(&m);
+ namemap_t m2 = NAMEMAP_INIT();
+
+ tt_uint_op(0, OP_EQ, namemap_get_size(&m));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, "hello"));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, "hello"));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, "hello128"));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, ""));
+ tt_uint_op(0, OP_EQ, namemap_get_size(&m));
+
+ tt_uint_op(0, OP_EQ, namemap_get_size(&m2));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m2, "hello"));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m2, "hello"));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m2, "hello128"));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m2, ""));
+ tt_uint_op(0, OP_EQ, namemap_get_size(&m));
+
+ done:
+ namemap_clear(&m);
+ namemap_clear(&m2);
+}
+
+static void
+test_namemap_toolong(void *arg)
+{
+ (void)arg;
+ namemap_t m;
+ char *ok = NULL;
+ char *toolong = NULL;
+ namemap_init(&m);
+
+ ok = tor_malloc_zero(MAX_NAMEMAP_NAME_LEN+1);
+ memset(ok, 'x', MAX_NAMEMAP_NAME_LEN);
+
+ toolong = tor_malloc_zero(MAX_NAMEMAP_NAME_LEN+2);
+ memset(toolong, 'x', MAX_NAMEMAP_NAME_LEN+1);
+
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, ok));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, toolong));
+ unsigned u1 = namemap_get_or_create_id(&m, toolong);
+ unsigned u2 = namemap_get_or_create_id(&m, ok);
+ tt_uint_op(u1, OP_EQ, NAMEMAP_ERR);
+ tt_uint_op(u2, OP_NE, NAMEMAP_ERR);
+ tt_uint_op(u2, OP_EQ, namemap_get_id(&m, ok));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, toolong));
+
+ tt_str_op(ok, OP_EQ, namemap_get_name(&m, u2));
+ tt_ptr_op(NULL, OP_EQ, namemap_get_name(&m, u1));
+
+ done:
+ tor_free(ok);
+ tor_free(toolong);
+ namemap_clear(&m);
+}
+
+static void
+test_namemap_blackbox(void *arg)
+{
+ (void)arg;
+
+ namemap_t m1, m2;
+ namemap_init(&m1);
+ namemap_init(&m2);
+
+ unsigned u1 = namemap_get_or_create_id(&m1, "hello");
+ unsigned u2 = namemap_get_or_create_id(&m1, "world");
+ tt_uint_op(u1, OP_NE, NAMEMAP_ERR);
+ tt_uint_op(u2, OP_NE, NAMEMAP_ERR);
+ tt_uint_op(u1, OP_NE, u2);
+
+ tt_uint_op(u1, OP_EQ, namemap_get_id(&m1, "hello"));
+ tt_uint_op(u1, OP_EQ, namemap_get_or_create_id(&m1, "hello"));
+ tt_uint_op(u2, OP_EQ, namemap_get_id(&m1, "world"));
+ tt_uint_op(u2, OP_EQ, namemap_get_or_create_id(&m1, "world"));
+
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m1, "HELLO"));
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m2, "hello"));
+
+ unsigned u3 = namemap_get_or_create_id(&m2, "hola");
+ tt_uint_op(u3, OP_NE, NAMEMAP_ERR);
+ tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m1, "hola"));
+ tt_uint_op(u3, OP_EQ, namemap_get_or_create_id(&m2, "hola"));
+ tt_uint_op(u3, OP_EQ, namemap_get_id(&m2, "hola"));
+
+ unsigned int u4 = namemap_get_or_create_id(&m1, "hola");
+ tt_uint_op(u4, OP_NE, NAMEMAP_ERR);
+ tt_uint_op(u4, OP_EQ, namemap_get_id(&m1, "hola"));
+ tt_uint_op(u3, OP_EQ, namemap_get_id(&m2, "hola"));
+
+ tt_str_op("hello", OP_EQ, namemap_get_name(&m1, u1));
+ tt_str_op("world", OP_EQ, namemap_get_name(&m1, u2));
+ tt_str_op("hola", OP_EQ, namemap_get_name(&m2, u3));
+ tt_str_op("hola", OP_EQ, namemap_get_name(&m1, u4));
+
+ tt_ptr_op(NULL, OP_EQ, namemap_get_name(&m2, u3 + 10));
+
+ done:
+ namemap_clear(&m1);
+ namemap_clear(&m2);
+}
+
+static void
+test_namemap_internals(void *arg)
+{
+ (void)arg;
+ // This test actually assumes know something about the identity layout.
+ namemap_t m;
+ namemap_init(&m);
+
+ tt_uint_op(0, OP_EQ, namemap_get_or_create_id(&m, "that"));
+ tt_uint_op(0, OP_EQ, namemap_get_or_create_id(&m, "that"));
+ tt_uint_op(1, OP_EQ, namemap_get_or_create_id(&m, "is"));
+ tt_uint_op(1, OP_EQ, namemap_get_or_create_id(&m, "is"));
+
+ tt_uint_op(0, OP_EQ, namemap_get_id(&m, "that"));
+ tt_uint_op(0, OP_EQ, namemap_get_id(&m, "that"));
+ tt_uint_op(1, OP_EQ, namemap_get_id(&m, "is"));
+ tt_uint_op(2, OP_EQ, namemap_get_or_create_id(&m, "not"));
+ tt_uint_op(1, OP_EQ, namemap_get_or_create_id(&m, "is"));
+ tt_uint_op(2, OP_EQ, namemap_get_or_create_id(&m, "not"));
+
+ done:
+ namemap_clear(&m);
+}
+
+static void
+test_namemap_fmt(void *arg)
+{
+ (void)arg;
+ namemap_t m = NAMEMAP_INIT();
+
+ unsigned a = namemap_get_or_create_id(&m, "greetings");
+ unsigned b = namemap_get_or_create_id(&m, "earthlings");
+
+ tt_str_op(namemap_fmt_name(&m, a), OP_EQ, "greetings");
+ tt_str_op(namemap_fmt_name(&m, b), OP_EQ, "earthlings");
+ tt_int_op(a, OP_NE, 100);
+ tt_int_op(b, OP_NE, 100);
+ tt_str_op(namemap_fmt_name(&m, 100), OP_EQ, "{100}");
+
+ done:
+ namemap_clear(&m);
+}
+
+#define T(name) \
+ { #name, test_namemap_ ## name , 0, NULL, NULL }
+
+struct testcase_t namemap_tests[] = {
+ T(empty),
+ T(toolong),
+ T(blackbox),
+ T(internals),
+ T(fmt),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_netinfo.c b/src/test/test_netinfo.c
new file mode 100644
index 0000000000..93892978dc
--- /dev/null
+++ b/src/test/test_netinfo.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "trunnel/netinfo.h"
+#include "test/test.h"
+
+static void
+test_netinfo_unsupported_addr(void *arg)
+{
+ const uint8_t wire_data[] =
+ { // TIME
+ 0x00, 0x00, 0x00, 0x01,
+ // OTHERADDR
+ 0x04, // ATYPE
+ 0x04, // ALEN
+ 0x08, 0x08, 0x08, 0x08, // AVAL
+ 0x01, // NMYADDR
+ 0x03, // ATYPE (unsupported)
+ 0x05, // ALEN
+ 'a', 'd', 'r', 'r', '!' // AVAL (unsupported)
+ };
+
+ (void)arg;
+
+ netinfo_cell_t *parsed_cell = NULL;
+
+ ssize_t parsed = netinfo_cell_parse(&parsed_cell, wire_data,
+ sizeof(wire_data));
+
+ tt_assert(parsed == sizeof(wire_data));
+
+ netinfo_addr_t *addr = netinfo_cell_get_my_addrs(parsed_cell, 0);
+ tt_assert(addr);
+
+ tt_int_op(3, OP_EQ, netinfo_addr_get_addr_type(addr));
+ tt_int_op(5, OP_EQ, netinfo_addr_get_len(addr));
+
+ done:
+ netinfo_cell_free(parsed_cell);
+}
+
+struct testcase_t netinfo_tests[] = {
+ { "unsupported_addr", test_netinfo_unsupported_addr, 0, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c
index 53eb0413e5..96fb5a65ad 100644
--- a/src/test/test_nodelist.c
+++ b/src/test/test_nodelist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,15 +6,25 @@
* \brief Unit tests for nodelist related functions.
**/
+#define NODELIST_PRIVATE
+#define NETWORKSTATUS_PRIVATE
+
#include "core/or/or.h"
#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/crypt_ops/crypto_format.h"
+#include "feature/nodelist/describe.h"
#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/nodefamily.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/torcert.h"
+#include "core/or/extend_info_st.h"
+#include "feature/dirauth/dirvote.h"
+#include "feature/nodelist/fmt_routerstatus.h"
#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/nodefamily_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerstatus_st.h"
@@ -72,7 +82,7 @@ test_nodelist_node_get_verbose_nickname_not_named(void *arg)
}
/** A node should be considered a directory server if it has an open dirport
- * of it accepts tunnelled directory requests.
+ * or it accepts tunnelled directory requests.
*/
static void
test_nodelist_node_is_dir(void *arg)
@@ -95,7 +105,7 @@ test_nodelist_node_is_dir(void *arg)
tt_assert(node_is_dir(&node));
rs.is_v2_dir = 0;
- rs.dir_port = 1;
+ rs.ipv4_dirport = 1;
tt_assert(! node_is_dir(&node));
node.rs = NULL;
@@ -104,7 +114,7 @@ test_nodelist_node_is_dir(void *arg)
ri.supports_tunnelled_dir_requests = 1;
tt_assert(node_is_dir(&node));
ri.supports_tunnelled_dir_requests = 0;
- ri.dir_port = 1;
+ ri.ipv4_dirport = 1;
tt_assert(! node_is_dir(&node));
done:
@@ -231,6 +241,1187 @@ test_nodelist_ed_id(void *arg)
#undef N_NODES
}
+static void
+test_nodelist_nodefamily(void *arg)
+{
+ (void)arg;
+ /* hex ID digests */
+ const char h1[] = "5B435D6869206861206C65207363617270652070";
+ const char h2[] = "75C3B220616E6461726520696E206769726F2061";
+ const char h3[] = "2074726F766172206461206D616E67696172652C";
+ const char h4[] = "206D656E747265206E6F6E2076616C65206C2769";
+ const char h5[] = "6E766572736F2E202D2D5072696D6F204C657669";
+
+ /* binary ID digests */
+ uint8_t d1[DIGEST_LEN], d2[DIGEST_LEN], d3[DIGEST_LEN], d4[DIGEST_LEN],
+ d5[DIGEST_LEN];
+ base16_decode((char*)d1, sizeof(d1), h1, strlen(h1));
+ base16_decode((char*)d2, sizeof(d2), h2, strlen(h2));
+ base16_decode((char*)d3, sizeof(d3), h3, strlen(h3));
+ base16_decode((char*)d4, sizeof(d4), h4, strlen(h4));
+ base16_decode((char*)d5, sizeof(d5), h5, strlen(h5));
+
+ char *enc=NULL, *enc2=NULL;
+
+ nodefamily_t *nf1 = NULL;
+ nodefamily_t *nf2 = NULL;
+ nodefamily_t *nf3 = NULL;
+
+ enc = nodefamily_format(NULL);
+ tt_str_op(enc, OP_EQ, "");
+ tor_free(enc);
+
+ /* Make sure that sorting and de-duplication work. */
+ tor_asprintf(&enc, "$%s hello", h1);
+ nf1 = nodefamily_parse(enc, NULL, 0);
+ tt_assert(nf1);
+ tor_free(enc);
+
+ tor_asprintf(&enc, "hello hello $%s hello", h1);
+ nf2 = nodefamily_parse(enc, NULL, 0);
+ tt_assert(nf2);
+ tt_ptr_op(nf1, OP_EQ, nf2);
+ tor_free(enc);
+
+ tor_asprintf(&enc, "%s $%s hello", h1, h1);
+ nf3 = nodefamily_parse(enc, NULL, 0);
+ tt_assert(nf3);
+ tt_ptr_op(nf1, OP_EQ, nf3);
+ tor_free(enc);
+
+ tt_assert(nodefamily_contains_rsa_id(nf1, d1));
+ tt_assert(! nodefamily_contains_rsa_id(nf1, d2));
+ tt_assert(nodefamily_contains_nickname(nf1, "hello"));
+ tt_assert(nodefamily_contains_nickname(nf1, "HELLO"));
+ tt_assert(! nodefamily_contains_nickname(nf1, "goodbye"));
+
+ tt_int_op(nf1->refcnt, OP_EQ, 3);
+ nodefamily_free(nf3);
+ tt_int_op(nf1->refcnt, OP_EQ, 2);
+
+ /* Try parsing with a provided self RSA digest. */
+ nf3 = nodefamily_parse("hello ", d1, 0);
+ tt_assert(nf3);
+ tt_ptr_op(nf1, OP_EQ, nf3);
+
+ /* Do we get the expected result when we re-encode? */
+ tor_asprintf(&enc, "$%s hello", h1);
+ enc2 = nodefamily_format(nf1);
+ tt_str_op(enc2, OP_EQ, enc);
+ tor_free(enc2);
+ tor_free(enc);
+
+ /* Make sure that we get a different result if we give a different digest. */
+ nodefamily_free(nf3);
+ tor_asprintf(&enc, "hello $%s hello", h3);
+ nf3 = nodefamily_parse(enc, NULL, 0);
+ tt_assert(nf3);
+ tt_ptr_op(nf1, OP_NE, nf3);
+ tor_free(enc);
+
+ tt_assert(nodefamily_contains_rsa_id(nf3, d3));
+ tt_assert(! nodefamily_contains_rsa_id(nf3, d2));
+ tt_assert(! nodefamily_contains_rsa_id(nf3, d1));
+ tt_assert(nodefamily_contains_nickname(nf3, "hello"));
+ tt_assert(! nodefamily_contains_nickname(nf3, "goodbye"));
+
+ nodefamily_free(nf1);
+ nodefamily_free(nf2);
+ nodefamily_free(nf3);
+
+ /* Try one with several digests, all with nicknames appended, in different
+ formats. */
+ tor_asprintf(&enc, "%s $%s $%s=res $%s~ist", h1, h2, h3, h4);
+ nf1 = nodefamily_parse(enc, d5, 0);
+ tt_assert(nf1);
+ tt_assert(nodefamily_contains_rsa_id(nf1, d1));
+ tt_assert(nodefamily_contains_rsa_id(nf1, d2));
+ tt_assert(nodefamily_contains_rsa_id(nf1, d3));
+ tt_assert(nodefamily_contains_rsa_id(nf1, d4));
+ tt_assert(nodefamily_contains_rsa_id(nf1, d5));
+ /* Nicknames aren't preserved when ids are present, since node naming is
+ * deprecated */
+ tt_assert(! nodefamily_contains_nickname(nf3, "res"));
+ tor_free(enc);
+ tor_asprintf(&enc, "$%s $%s $%s $%s $%s", h4, h3, h1, h5, h2);
+ enc2 = nodefamily_format(nf1);
+ tt_str_op(enc, OP_EQ, enc2);
+ tor_free(enc);
+ tor_free(enc2);
+
+ /* Try ones where we parse the empty string. */
+ nf2 = nodefamily_parse("", NULL, 0);
+ nf3 = nodefamily_parse("", d4, 0);
+ tt_assert(nf2);
+ tt_assert(nf3);
+ tt_ptr_op(nf2, OP_NE, nf3);
+
+ tt_assert(! nodefamily_contains_rsa_id(nf2, d4));
+ tt_assert(nodefamily_contains_rsa_id(nf3, d4));
+ tt_assert(! nodefamily_contains_rsa_id(nf2, d5));
+ tt_assert(! nodefamily_contains_rsa_id(nf3, d5));
+ tt_assert(! nodefamily_contains_nickname(nf2, "fred"));
+ tt_assert(! nodefamily_contains_nickname(nf3, "bosco"));
+
+ /* The NULL family should contain nothing. */
+ tt_assert(! nodefamily_contains_rsa_id(NULL, d4));
+ tt_assert(! nodefamily_contains_rsa_id(NULL, d5));
+
+ done:
+ tor_free(enc);
+ tor_free(enc2);
+ nodefamily_free(nf1);
+ nodefamily_free(nf2);
+ nodefamily_free(nf3);
+ nodefamily_free_all();
+}
+
+static void
+test_nodelist_nodefamily_parse_err(void *arg)
+{
+ (void)arg;
+ nodefamily_t *nf1 = NULL;
+ char *enc = NULL;
+ const char *semibogus =
+ "sdakljfdslkfjdsaklfjdkl9sdf " // too long for nickname
+ "$jkASDFLkjsadfjhkl " // not hex
+ "$7468696e67732d696e2d7468656d73656c766573 " // ok
+ "reticulatogranulate "// ok
+ "$73656d69616e7468726f706f6c6f676963616c6c79 " // too long for hex
+ "$616273656e746d696e6465646e6573736573" // too short for hex
+ ;
+
+ setup_capture_of_logs(LOG_WARN);
+
+ // We only get two items when we parse this.
+ for (int reject = 0; reject <= 1; ++reject) {
+ for (int log_at_warn = 0; log_at_warn <= 1; ++log_at_warn) {
+ unsigned flags = log_at_warn ? NF_WARN_MALFORMED : 0;
+ flags |= reject ? NF_REJECT_MALFORMED : 0;
+ nf1 = nodefamily_parse(semibogus, NULL, flags);
+ if (reject) {
+ tt_assert(nf1 == NULL);
+ } else {
+ tt_assert(nf1);
+ enc = nodefamily_format(nf1);
+ tt_str_op(enc, OP_EQ,
+ "$7468696E67732D696E2D7468656D73656C766573 "
+ "reticulatogranulate");
+ tor_free(enc);
+ }
+
+ if (log_at_warn) {
+ expect_log_msg_containing("$616273656e746d696e6465646e6573736573");
+ expect_log_msg_containing("sdakljfdslkfjdsaklfjdkl9sdf");
+ } else {
+ tt_int_op(mock_saved_log_n_entries(), OP_EQ, 0);
+ }
+ mock_clean_saved_logs();
+ }
+ }
+
+ done:
+ tor_free(enc);
+ nodefamily_free(nf1);
+ teardown_capture_of_logs();
+}
+
+static const node_t *
+mock_node_get_by_id(const char *id)
+{
+ if (fast_memeq(id, "!!!!!!!!!!!!!!!!!!!!", DIGEST_LEN))
+ return NULL;
+
+ // use tor_free, not node_free.
+ node_t *fake_node = tor_malloc_zero(sizeof(node_t));
+ memcpy(fake_node->identity, id, DIGEST_LEN);
+ return fake_node;
+}
+
+static const node_t *
+mock_node_get_by_nickname(const char *nn, unsigned flags)
+{
+ (void)flags;
+ if (!strcmp(nn, "nonesuch"))
+ return NULL;
+
+ // use tor_free, not node_free.
+ node_t *fake_node = tor_malloc_zero(sizeof(node_t));
+ strlcpy(fake_node->identity, nn, DIGEST_LEN);
+ return fake_node;
+}
+
+static void
+test_nodelist_nodefamily_lookup(void *arg)
+{
+ (void)arg;
+ MOCK(node_get_by_nickname, mock_node_get_by_nickname);
+ MOCK(node_get_by_id, mock_node_get_by_id);
+ smartlist_t *sl = smartlist_new();
+ nodefamily_t *nf1 = NULL;
+ char *mem_op_hex_tmp = NULL;
+
+ // 'null' is allowed.
+ nodefamily_add_nodes_to_smartlist(NULL, sl);
+ tt_int_op(smartlist_len(sl), OP_EQ, 0);
+
+ // Try a real family
+ nf1 = nodefamily_parse("$EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE "
+ "$2121212121212121212121212121212121212121 "
+ "$3333333333333333333333333333333333333333 "
+ "erewhon nonesuch", NULL, 0);
+ tt_assert(nf1);
+ nodefamily_add_nodes_to_smartlist(nf1, sl);
+ // There were 5 elements; 2 were dropped because the mocked lookup failed.
+ tt_int_op(smartlist_len(sl), OP_EQ, 3);
+
+ const node_t *n = smartlist_get(sl, 0);
+ test_memeq_hex(n->identity, "3333333333333333333333333333333333333333");
+ n = smartlist_get(sl, 1);
+ test_memeq_hex(n->identity, "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE");
+ n = smartlist_get(sl, 2);
+ tt_str_op(n->identity, OP_EQ, "erewhon");
+
+ done:
+ UNMOCK(node_get_by_nickname);
+ UNMOCK(node_get_by_id);
+ SMARTLIST_FOREACH(sl, node_t *, fake_node, tor_free(fake_node));
+ smartlist_free(sl);
+ nodefamily_free(nf1);
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_nodelist_nickname_matches(void *arg)
+{
+ (void)arg;
+ node_t mock_node;
+ routerstatus_t mock_rs;
+ memset(&mock_node, 0, sizeof(mock_node));
+ memset(&mock_rs, 0, sizeof(mock_rs));
+
+ strlcpy(mock_rs.nickname, "evilgeniuses", sizeof(mock_rs.nickname));
+ mock_node.rs = &mock_rs;
+ memcpy(mock_node.identity, ".forabettertomorrow.", DIGEST_LEN);
+
+#define match(x) tt_assert(node_nickname_matches(&mock_node, (x)))
+#define no_match(x) tt_assert(! node_nickname_matches(&mock_node, (x)))
+
+ match("evilgeniuses");
+ match("EvilGeniuses");
+ match("EvilGeniuses");
+ match("2e666f7261626574746572746f6d6f72726f772e");
+ match("2E666F7261626574746572746F6D6F72726F772E");
+ match("$2e666f7261626574746572746f6d6f72726f772e");
+ match("$2E666F7261626574746572746F6D6F72726F772E");
+ match("$2E666F7261626574746572746F6D6F72726F772E~evilgeniuses");
+ match("$2E666F7261626574746572746F6D6F72726F772E~EVILGENIUSES");
+
+ no_match("evilgenius");
+ no_match("evilgeniuseses");
+ no_match("evil.genius");
+ no_match("$2E666F7261626574746572746F6D6F72726FFFFF");
+ no_match("2E666F7261626574746572746F6D6F72726FFFFF");
+ no_match("$2E666F7261626574746572746F6D6F72726F772E~fred");
+ no_match("$2E666F7261626574746572746F6D6F72726F772E=EVILGENIUSES");
+ done:
+ ;
+}
+
+static void
+test_nodelist_node_nodefamily(void *arg)
+{
+ (void)arg;
+ node_t mock_node1;
+ routerstatus_t mock_rs;
+ microdesc_t mock_md;
+
+ node_t mock_node2;
+ routerinfo_t mock_ri;
+
+ smartlist_t *nodes=smartlist_new();
+
+ memset(&mock_node1, 0, sizeof(mock_node1));
+ memset(&mock_node2, 0, sizeof(mock_node2));
+ memset(&mock_rs, 0, sizeof(mock_rs));
+ memset(&mock_md, 0, sizeof(mock_md));
+ memset(&mock_ri, 0, sizeof(mock_ri));
+
+ mock_node1.rs = &mock_rs;
+ mock_node1.md = &mock_md;
+
+ mock_node2.ri = &mock_ri;
+
+ strlcpy(mock_rs.nickname, "nodeone", sizeof(mock_rs.nickname));
+ mock_ri.nickname = tor_strdup("nodetwo");
+
+ memcpy(mock_node1.identity, "NodeOneNode1NodeOne1", DIGEST_LEN);
+ memcpy(mock_node2.identity, "SecondNodeWe'reTestn", DIGEST_LEN);
+
+ // empty families.
+ tt_assert(! node_family_contains(&mock_node1, &mock_node2));
+ tt_assert(! node_family_contains(&mock_node2, &mock_node1));
+
+ // Families contain nodes, but not these nodes
+ mock_ri.declared_family = smartlist_new();
+ smartlist_add(mock_ri.declared_family, (char*)"NodeThree");
+ mock_md.family = nodefamily_parse("NodeFour", NULL, 0);
+ tt_assert(! node_family_contains(&mock_node1, &mock_node2));
+ tt_assert(! node_family_contains(&mock_node2, &mock_node1));
+
+ // Families contain one another.
+ smartlist_add(mock_ri.declared_family, (char*)
+ "4e6f64654f6e654e6f6465314e6f64654f6e6531");
+ tt_assert(! node_family_contains(&mock_node1, &mock_node2));
+ tt_assert(node_family_contains(&mock_node2, &mock_node1));
+
+ nodefamily_free(mock_md.family);
+ mock_md.family = nodefamily_parse(
+ "NodeFour "
+ "5365636f6e644e6f64655765277265546573746e", NULL, 0);
+ tt_assert(node_family_contains(&mock_node1, &mock_node2));
+ tt_assert(node_family_contains(&mock_node2, &mock_node1));
+
+ // Try looking up families now.
+ MOCK(node_get_by_nickname, mock_node_get_by_nickname);
+ MOCK(node_get_by_id, mock_node_get_by_id);
+
+ node_lookup_declared_family(nodes, &mock_node1);
+ tt_int_op(smartlist_len(nodes), OP_EQ, 2);
+ const node_t *n = smartlist_get(nodes, 0);
+ tt_mem_op(n->identity, OP_EQ, "SecondNodeWe'reTestn", DIGEST_LEN);
+ n = smartlist_get(nodes, 1);
+ tt_str_op(n->identity, OP_EQ, "nodefour");
+
+ // free, try the other one.
+ SMARTLIST_FOREACH(nodes, node_t *, x, tor_free(x));
+ smartlist_clear(nodes);
+
+ node_lookup_declared_family(nodes, &mock_node2);
+ tt_int_op(smartlist_len(nodes), OP_EQ, 2);
+ n = smartlist_get(nodes, 0);
+ // This gets a truncated hex hex ID since it was looked up by name
+ tt_str_op(n->identity, OP_EQ, "NodeThree");
+ n = smartlist_get(nodes, 1);
+ tt_str_op(n->identity, OP_EQ, "4e6f64654f6e654e6f6");
+
+ done:
+ UNMOCK(node_get_by_nickname);
+ UNMOCK(node_get_by_id);
+ smartlist_free(mock_ri.declared_family);
+ nodefamily_free(mock_md.family);
+ tor_free(mock_ri.nickname);
+ // use tor_free, these aren't real nodes
+ SMARTLIST_FOREACH(nodes, node_t *, x, tor_free(x));
+ smartlist_free(nodes);
+}
+
+static void
+test_nodelist_nodefamily_canonicalize(void *arg)
+{
+ (void)arg;
+ char *c = NULL;
+
+ c = nodefamily_canonicalize("", NULL, 0);
+ tt_str_op(c, OP_EQ, "");
+ tor_free(c);
+
+ uint8_t own_id[20];
+ memset(own_id, 0, sizeof(own_id));
+ c = nodefamily_canonicalize(
+ "alice BOB caroL %potrzebie !!!@#@# "
+ "$bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=fred "
+ "ffffffffffffffffffffffffffffffffffffffff "
+ "$cccccccccccccccccccccccccccccccccccccccc ", own_id, 0);
+ tt_str_op(c, OP_EQ,
+ "!!!@#@# "
+ "$0000000000000000000000000000000000000000 "
+ "$BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB "
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC "
+ "$FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF "
+ "%potrzebie "
+ "alice bob carol");
+
+ done:
+ tor_free(c);
+}
+
+/** format_node_description() should return
+ * "Fingerprint~Nickname at IPv4 and [IPv6]".
+ * The nickname and addresses are optional.
+ */
+static void
+test_nodelist_format_node_description(void *arg)
+{
+ char mock_digest[DIGEST_LEN];
+ char mock_nickname[MAX_NICKNAME_LEN+1];
+ tor_addr_t mock_null_ip;
+ tor_addr_t mock_ipv4;
+ tor_addr_t mock_ipv6;
+ ed25519_public_key_t ed_id;
+
+ char ndesc[NODE_DESC_BUF_LEN];
+ const char *rv = NULL;
+
+ (void) arg;
+
+ /* Clear variables */
+ memset(ndesc, 0, sizeof(ndesc));
+ memset(mock_digest, 0, sizeof(mock_digest));
+ memset(mock_nickname, 0, sizeof(mock_nickname));
+ memset(&mock_null_ip, 0, sizeof(mock_null_ip));
+ memset(&mock_ipv4, 0, sizeof(mock_ipv4));
+ memset(&mock_ipv6, 0, sizeof(mock_ipv6));
+
+ /* Set variables */
+ memcpy(mock_digest,
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ sizeof(mock_digest));
+ strlcpy(mock_nickname, "TestOR7890123456789", sizeof(mock_nickname));
+ tor_addr_parse(&mock_ipv4, "111.222.233.244");
+ tor_addr_parse(&mock_ipv6, "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ /* Test function with variables */
+ rv = format_node_description(ndesc,
+ mock_digest,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ tt_ptr_op(rv, OP_EQ, ndesc);
+ tt_str_op(ndesc, OP_EQ, "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+
+ /* format node description should use ~ because named is deprecated */
+ rv = format_node_description(ndesc,
+ mock_digest,
+ NULL,
+ mock_nickname,
+ NULL,
+ NULL);
+ tt_ptr_op(rv, OP_EQ, ndesc);
+ tt_str_op(ndesc, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~""TestOR7890123456789");
+
+ /* Try a null IP address, rather than NULL */
+ rv = format_node_description(ndesc,
+ mock_digest,
+ NULL,
+ mock_nickname,
+ NULL,
+ &mock_null_ip);
+ tt_ptr_op(rv, OP_EQ, ndesc);
+ tt_str_op(ndesc, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789");
+
+ /* Try some real IP addresses */
+ rv = format_node_description(ndesc,
+ mock_digest,
+ NULL,
+ NULL,
+ &mock_ipv4,
+ NULL);
+ tt_ptr_op(rv, OP_EQ, ndesc);
+ tt_str_op(ndesc, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA at 111.222.233.244");
+
+ rv = format_node_description(ndesc,
+ mock_digest,
+ NULL,
+ mock_nickname,
+ NULL,
+ &mock_ipv6);
+ tt_ptr_op(rv, OP_EQ, ndesc);
+ tt_str_op(ndesc, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ rv = format_node_description(ndesc,
+ mock_digest,
+ NULL,
+ mock_nickname,
+ &mock_ipv4,
+ &mock_ipv6);
+ tt_ptr_op(rv, OP_EQ, ndesc);
+ tt_str_op(ndesc, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "111.222.233.244 and [1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ /* Try some ed25519 keys. */
+ int n = ed25519_public_from_base64(&ed_id,
+ "+wBP6WVZzqKK+eTdwU7Hhb80xEm40FSZDBMNozTJpDE");
+ tt_int_op(n,OP_EQ,0);
+ rv = format_node_description(ndesc,
+ mock_digest,
+ &ed_id,
+ mock_nickname,
+ &mock_ipv4,
+ &mock_ipv6);
+ tt_str_op(ndesc, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 "
+ "[+wBP6WVZzqKK+eTdwU7Hhb80xEm40FSZDBMNozTJpDE] at "
+ "111.222.233.244 and [1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ /* test NULL handling */
+ rv = format_node_description(NULL, NULL, NULL, NULL, NULL, NULL);
+ tt_str_op(rv, OP_EQ, "<NULL BUFFER>");
+
+ rv = format_node_description(ndesc, NULL, NULL, NULL, NULL, NULL);
+ tt_ptr_op(rv, OP_EQ, ndesc);
+ tt_str_op(rv, OP_EQ, "<NULL ID DIGEST>");
+
+ done:
+ return;
+}
+
+/** router_describe() is a wrapper for format_node_description(), see that
+ * test for details.
+ *
+ * The routerinfo-only node_describe() tests are in this function,
+ * so we can re-use the same mocked variables.
+ */
+static void
+test_nodelist_router_describe(void *arg)
+{
+ char mock_nickname[MAX_NICKNAME_LEN+1];
+ routerinfo_t mock_ri_ipv4;
+ routerinfo_t mock_ri_ipv6;
+ routerinfo_t mock_ri_dual;
+
+ const char *rv = NULL;
+
+ (void) arg;
+
+ /* Clear variables */
+ memset(mock_nickname, 0, sizeof(mock_nickname));
+ memset(&mock_ri_ipv4, 0, sizeof(mock_ri_ipv4));
+ memset(&mock_ri_ipv6, 0, sizeof(mock_ri_ipv6));
+ memset(&mock_ri_dual, 0, sizeof(mock_ri_dual));
+
+ /* Set up the dual-stack routerinfo */
+ memcpy(mock_ri_dual.cache_info.identity_digest,
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ sizeof(mock_ri_dual.cache_info.identity_digest));
+ strlcpy(mock_nickname, "TestOR7890123456789", sizeof(mock_nickname));
+ mock_ri_dual.nickname = mock_nickname;
+ tor_addr_parse(&mock_ri_dual.ipv4_addr, "111.222.233.244");
+ tor_addr_parse(&mock_ri_dual.ipv6_addr,
+ "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ /* Create and modify the other routerinfos.
+ * mock_nickname is referenced from all 3 routerinfos.
+ * That's ok, all their memory is static. */
+ memcpy(&mock_ri_ipv4, &mock_ri_dual, sizeof(mock_ri_ipv4));
+ memcpy(&mock_ri_ipv6, &mock_ri_dual, sizeof(mock_ri_ipv6));
+ /* Clear the unnecessary addresses */
+ memset(&mock_ri_ipv4.ipv6_addr, 0, sizeof(mock_ri_ipv4.ipv6_addr));
+ tor_addr_make_unspec(&mock_ri_ipv6.ipv4_addr);
+
+ /* We don't test the no-nickname and no-IP cases, because they're covered by
+ * format_node_description(), and we don't expect to see them in Tor code. */
+
+ /* Try some real IP addresses */
+ rv = router_describe(&mock_ri_ipv4);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "111.222.233.244");
+
+ rv = router_describe(&mock_ri_ipv6);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ rv = router_describe(&mock_ri_dual);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "111.222.233.244 and [1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ /* test NULL handling */
+ rv = router_describe(NULL);
+ tt_str_op(rv, OP_EQ, "<null>");
+
+ /* Now test a node with only these routerinfos */
+ node_t mock_node;
+ memset(&mock_node, 0, sizeof(mock_node));
+ memcpy(mock_node.identity,
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ sizeof(mock_node.identity));
+
+ /* Try some real IP addresses */
+ mock_node.ri = &mock_ri_ipv4;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "111.222.233.244");
+
+ mock_node.ri = &mock_ri_ipv6;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ mock_node.ri = &mock_ri_dual;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "111.222.233.244 and [1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ done:
+ return;
+}
+
+/** node_describe() is a wrapper for format_node_description(), see that
+ * test for details.
+ *
+ * The routerinfo-only and routerstatus-only node_describe() tests are in
+ * test_nodelist_router_describe() and test_nodelist_routerstatus_describe(),
+ * so we can re-use their mocked variables.
+ */
+static void
+test_nodelist_node_describe(void *arg)
+{
+ char mock_nickname[MAX_NICKNAME_LEN+1];
+
+ const char *rv = NULL;
+
+ (void) arg;
+
+ /* Routerinfos */
+ routerinfo_t mock_ri_dual;
+
+ /* Clear variables */
+ memset(mock_nickname, 0, sizeof(mock_nickname));
+ memset(&mock_ri_dual, 0, sizeof(mock_ri_dual));
+
+ /* Set up the dual-stack routerinfo */
+ memcpy(mock_ri_dual.cache_info.identity_digest,
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ sizeof(mock_ri_dual.cache_info.identity_digest));
+ strlcpy(mock_nickname, "TestOR7890123456789", sizeof(mock_nickname));
+ mock_ri_dual.nickname = mock_nickname;
+ tor_addr_parse(&mock_ri_dual.ipv4_addr, "111.222.233.244");
+ tor_addr_parse(&mock_ri_dual.ipv6_addr,
+ "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ /* Routerstatuses */
+ routerstatus_t mock_rs_ipv4;
+ routerstatus_t mock_rs_dual;
+
+ /* Clear variables */
+ memset(&mock_rs_ipv4, 0, sizeof(mock_rs_ipv4));
+ memset(&mock_rs_dual, 0, sizeof(mock_rs_dual));
+
+ /* Set up the dual-stack routerstatus */
+ memcpy(mock_rs_dual.identity_digest,
+ "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB"
+ "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB",
+ sizeof(mock_rs_dual.identity_digest));
+ strlcpy(mock_rs_dual.nickname, "Bbb",
+ sizeof(mock_rs_dual.nickname));
+ tor_addr_parse(&mock_rs_dual.ipv4_addr, "2.2.2.2");
+ tor_addr_parse(&mock_rs_dual.ipv6_addr,
+ "[bbbb::bbbb]");
+
+ /* Create and modify the other routerstatus. */
+ memcpy(&mock_rs_ipv4, &mock_rs_dual, sizeof(mock_rs_ipv4));
+ /* Clear the unnecessary IPv6 address */
+ memset(&mock_rs_ipv4.ipv6_addr, 0, sizeof(mock_rs_ipv4.ipv6_addr));
+
+ /* Microdescs */
+ microdesc_t mock_md_null;
+ microdesc_t mock_md_ipv6;
+
+ /* Clear variables */
+ memset(&mock_md_null, 0, sizeof(mock_md_null));
+ memset(&mock_md_ipv6, 0, sizeof(mock_md_ipv6));
+
+ /* Set up the microdesc */
+ tor_addr_parse(&mock_md_ipv6.ipv6_addr,
+ "[eeee::6000:6000]");
+
+ /* Set up the node */
+ node_t mock_node;
+ memset(&mock_node, 0, sizeof(mock_node));
+ memcpy(mock_node.identity,
+ "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC"
+ "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC",
+ sizeof(mock_node.identity));
+
+ /* Test that the routerinfo and routerstatus work separately, but the
+ * identity comes from the node */
+ mock_node.ri = &mock_ri_dual;
+ mock_node.rs = NULL;
+ mock_node.md = NULL;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~TestOR7890123456789 at "
+ "111.222.233.244 and [1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ mock_node.ri = NULL;
+ mock_node.rs = &mock_rs_ipv4;
+ mock_node.md = NULL;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2");
+
+ mock_node.ri = NULL;
+ mock_node.rs = &mock_rs_dual;
+ mock_node.md = NULL;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2 and [bbbb::bbbb]");
+
+ /* Test that the routerstatus overrides the routerinfo */
+ mock_node.ri = &mock_ri_dual;
+ mock_node.rs = &mock_rs_ipv4;
+ mock_node.md = NULL;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2");
+
+ mock_node.ri = &mock_ri_dual;
+ mock_node.rs = &mock_rs_dual;
+ mock_node.md = NULL;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2 and [bbbb::bbbb]");
+
+ /* Test that the microdesc IPv6 is used if the routerinfo doesn't have IPv6
+ */
+ mock_node.ri = NULL;
+ mock_node.rs = &mock_rs_ipv4;
+ mock_node.md = &mock_md_ipv6;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2 and [eeee::6000:6000]");
+
+ mock_node.ri = NULL;
+ mock_node.rs = &mock_rs_ipv4;
+ mock_node.md = &mock_md_null;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2");
+
+ mock_node.ri = NULL;
+ mock_node.rs = &mock_rs_dual;
+ mock_node.md = &mock_md_ipv6;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2 and [bbbb::bbbb]");
+
+ mock_node.ri = NULL;
+ mock_node.rs = &mock_rs_dual;
+ mock_node.md = &mock_md_null;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2 and [bbbb::bbbb]");
+
+ /* Test that the routerinfo doesn't change the results above
+ */
+ mock_node.ri = &mock_ri_dual;
+ mock_node.rs = &mock_rs_ipv4;
+ mock_node.md = &mock_md_ipv6;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2 and [eeee::6000:6000]");
+
+ mock_node.ri = &mock_ri_dual;
+ mock_node.rs = &mock_rs_ipv4;
+ mock_node.md = &mock_md_null;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2");
+
+ mock_node.ri = &mock_ri_dual;
+ mock_node.rs = &mock_rs_dual;
+ mock_node.md = &mock_md_ipv6;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2 and [bbbb::bbbb]");
+
+ mock_node.ri = &mock_ri_dual;
+ mock_node.rs = &mock_rs_dual;
+ mock_node.md = &mock_md_null;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC~Bbb at "
+ "2.2.2.2 and [bbbb::bbbb]");
+
+ /* test NULL handling */
+ rv = node_describe(NULL);
+ tt_str_op(rv, OP_EQ, "<null>");
+
+ mock_node.ri = NULL;
+ mock_node.rs = NULL;
+ mock_node.md = NULL;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "<null rs and ri>");
+
+ done:
+ return;
+}
+
+/** routerstatus_describe() is a wrapper for format_node_description(), see
+ * that test for details.
+ *
+ * The routerstatus-only node_describe() tests are in this function,
+ * so we can re-use the same mocked variables.
+ */
+static void
+test_nodelist_routerstatus_describe(void *arg)
+{
+ routerstatus_t mock_rs_ipv4;
+ routerstatus_t mock_rs_ipv6;
+ routerstatus_t mock_rs_dual;
+
+ const char *rv = NULL;
+
+ (void) arg;
+
+ /* Clear variables */
+ memset(&mock_rs_ipv4, 0, sizeof(mock_rs_ipv4));
+ memset(&mock_rs_ipv6, 0, sizeof(mock_rs_ipv6));
+ memset(&mock_rs_dual, 0, sizeof(mock_rs_dual));
+
+ /* Set up the dual-stack routerstatus */
+ memcpy(mock_rs_dual.identity_digest,
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ sizeof(mock_rs_dual.identity_digest));
+ strlcpy(mock_rs_dual.nickname, "TestOR7890123456789",
+ sizeof(mock_rs_dual.nickname));
+ tor_addr_parse(&mock_rs_dual.ipv4_addr, "111.222.233.244");
+ tor_addr_parse(&mock_rs_dual.ipv6_addr,
+ "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ /* Create and modify the other routerstatuses. */
+ memcpy(&mock_rs_ipv4, &mock_rs_dual, sizeof(mock_rs_ipv4));
+ memcpy(&mock_rs_ipv6, &mock_rs_dual, sizeof(mock_rs_ipv6));
+ /* Clear the unnecessary addresses */
+ memset(&mock_rs_ipv4.ipv6_addr, 0, sizeof(mock_rs_ipv4.ipv6_addr));
+ tor_addr_make_unspec(&mock_rs_ipv6.ipv4_addr);
+
+ /* We don't test the no-nickname and no-IP cases, because they're covered by
+ * format_node_description(), and we don't expect to see them in Tor code. */
+
+ /* Try some real IP addresses */
+ rv = routerstatus_describe(&mock_rs_ipv4);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "111.222.233.244");
+
+ rv = routerstatus_describe(&mock_rs_ipv6);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ rv = routerstatus_describe(&mock_rs_dual);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "111.222.233.244 and [1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ /* test NULL handling */
+ rv = routerstatus_describe(NULL);
+ tt_str_op(rv, OP_EQ, "<null>");
+
+ /* Now test a node with only these routerstatuses */
+ node_t mock_node;
+ memset(&mock_node, 0, sizeof(mock_node));
+ memcpy(mock_node.identity,
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ sizeof(mock_node.identity));
+
+ /* Try some real IP addresses */
+ mock_node.rs = &mock_rs_ipv4;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "111.222.233.244");
+
+ mock_node.rs = &mock_rs_ipv6;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ mock_node.rs = &mock_rs_dual;
+ rv = node_describe(&mock_node);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "111.222.233.244 and [1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ done:
+ return;
+}
+
+/** extend_info_describe() is a wrapper for format_node_description(), see
+ * that test for details.
+ */
+static void
+test_nodelist_extend_info_describe(void *arg)
+{
+ extend_info_t mock_ei_ipv4;
+ extend_info_t mock_ei_ipv6;
+
+ const char *rv = NULL;
+
+ (void) arg;
+
+ /* Clear variables */
+ memset(&mock_ei_ipv4, 0, sizeof(mock_ei_ipv4));
+ memset(&mock_ei_ipv6, 0, sizeof(mock_ei_ipv6));
+
+ /* Set up the IPv4 extend info */
+ memcpy(mock_ei_ipv4.identity_digest,
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ sizeof(mock_ei_ipv4.identity_digest));
+ strlcpy(mock_ei_ipv4.nickname, "TestOR7890123456789",
+ sizeof(mock_ei_ipv4.nickname));
+ tor_addr_parse(&mock_ei_ipv4.orports[0].addr, "111.222.233.244");
+
+ /* Create and modify the other extend info. */
+ memcpy(&mock_ei_ipv6, &mock_ei_ipv4, sizeof(mock_ei_ipv6));
+ tor_addr_parse(&mock_ei_ipv6.orports[0].addr,
+ "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ /* We don't test the no-nickname and no-IP cases, because they're covered by
+ * format_node_description(), and we don't expect to see them in Tor code. */
+
+ /* Try some real IP addresses */
+ rv = extend_info_describe(&mock_ei_ipv4);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "111.222.233.244");
+
+ rv = extend_info_describe(&mock_ei_ipv6);
+ tt_str_op(rv, OP_EQ,
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
+ "[1111:2222:3333:4444:5555:6666:7777:8888]");
+
+ /* Extend infos only have one IP address, so there is no dual case */
+
+ /* test NULL handling */
+ rv = extend_info_describe(NULL);
+ tt_str_op(rv, OP_EQ, "<null>");
+
+ done:
+ return;
+}
+
+/** router_get_verbose_nickname() should return "Fingerprint~Nickname"
+ */
+static void
+test_nodelist_router_get_verbose_nickname(void *arg)
+{
+ routerinfo_t mock_ri;
+ char mock_nickname[MAX_NICKNAME_LEN+1];
+
+ char vname[MAX_VERBOSE_NICKNAME_LEN+1];
+
+ (void) arg;
+
+ memset(&mock_ri, 0, sizeof(routerinfo_t));
+ memset(mock_nickname, 0, sizeof(mock_nickname));
+ mock_ri.nickname = mock_nickname;
+
+ /* verbose nickname should use ~ because named is deprecated */
+ strlcpy(mock_nickname, "TestOR", sizeof(mock_nickname));
+ memcpy(mock_ri.cache_info.identity_digest,
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ DIGEST_LEN);
+ router_get_verbose_nickname(vname, &mock_ri);
+ tt_str_op(vname, OP_EQ, "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR");
+
+ /* test NULL router handling */
+ router_get_verbose_nickname(vname, NULL);
+ tt_str_op(vname, OP_EQ, "<null>");
+
+ router_get_verbose_nickname(NULL, &mock_ri);
+ router_get_verbose_nickname(NULL, NULL);
+
+ done:
+ return;
+}
+
+static void
+test_nodelist_routerstatus_has_visibly_changed(void *arg)
+{
+ (void)arg;
+ routerstatus_t rs_orig, rs;
+ char *fmt_orig = NULL, *fmt = NULL;
+ memset(&rs_orig, 0, sizeof(rs_orig));
+ strlcpy(rs_orig.nickname, "friendly", sizeof(rs_orig.nickname));
+ memcpy(rs_orig.identity_digest, "abcdefghijklmnopqrst", 20);
+ memcpy(rs_orig.descriptor_digest, "abcdefghijklmnopqrst", 20);
+ tor_addr_from_ipv4h(&rs_orig.ipv4_addr, 0x7f000001);
+ rs_orig.ipv4_orport = 3;
+ rs_orig.published_on = time(NULL);
+ rs_orig.has_bandwidth = 1;
+ rs_orig.bandwidth_kb = 20;
+
+#define COPY() memcpy(&rs, &rs_orig, sizeof(rs))
+#define FORMAT() \
+ STMT_BEGIN \
+ tor_free(fmt_orig); \
+ tor_free(fmt); \
+ fmt_orig = routerstatus_format_entry(&rs_orig, NULL, NULL, \
+ NS_CONTROL_PORT, \
+ NULL); \
+ fmt = routerstatus_format_entry(&rs, NULL, NULL, NS_CONTROL_PORT, \
+ NULL); \
+ tt_assert(fmt_orig); \
+ tt_assert(fmt); \
+ STMT_END
+#define ASSERT_SAME() \
+ STMT_BEGIN \
+ tt_assert(! routerstatus_has_visibly_changed(&rs_orig, &rs)); \
+ FORMAT(); \
+ tt_str_op(fmt_orig, OP_EQ, fmt); \
+ COPY(); \
+ STMT_END
+#define ASSERT_CHANGED() \
+ STMT_BEGIN \
+ tt_assert(routerstatus_has_visibly_changed(&rs_orig, &rs)); \
+ FORMAT(); \
+ tt_str_op(fmt_orig, OP_NE, fmt); \
+ COPY(); \
+ STMT_END
+#define ASSERT_CHANGED_NO_FORMAT() \
+ STMT_BEGIN \
+ tt_assert(routerstatus_has_visibly_changed(&rs_orig, &rs)); \
+ COPY(); \
+ STMT_END
+
+ COPY();
+ ASSERT_SAME();
+
+ tor_addr_from_ipv4h(&rs.ipv4_addr, 0x7f000002);
+ ASSERT_CHANGED();
+
+ strlcpy(rs.descriptor_digest, "hello world", sizeof(rs.descriptor_digest));
+ ASSERT_CHANGED();
+
+ strlcpy(rs.nickname, "fr1end1y", sizeof(rs.nickname));
+ ASSERT_CHANGED();
+
+ rs.published_on += 3600;
+ ASSERT_CHANGED();
+
+ rs.ipv4_orport = 55;
+ ASSERT_CHANGED();
+
+ rs.ipv4_dirport = 9999;
+ ASSERT_CHANGED();
+
+ tor_addr_parse(&rs.ipv6_addr, "1234::56");
+ ASSERT_CHANGED();
+
+ tor_addr_parse(&rs_orig.ipv6_addr, "1234::56");
+ rs_orig.ipv6_orport = 99;
+ COPY();
+ rs.ipv6_orport = 22;
+ ASSERT_CHANGED();
+
+ rs.is_authority = 1;
+ ASSERT_CHANGED();
+
+ rs.is_exit = 1;
+ ASSERT_CHANGED();
+
+ rs.is_stable = 1;
+ ASSERT_CHANGED();
+
+ rs.is_fast = 1;
+ ASSERT_CHANGED();
+
+ rs.is_flagged_running = 1;
+ ASSERT_CHANGED();
+
+ // This option is obsolete and not actually formatted.
+ rs.is_named = 1;
+ ASSERT_CHANGED_NO_FORMAT();
+
+ // This option is obsolete and not actually formatted.
+ rs.is_unnamed = 1;
+ ASSERT_CHANGED_NO_FORMAT();
+
+ rs.is_valid = 1;
+ ASSERT_CHANGED();
+
+ rs.is_possible_guard = 1;
+ ASSERT_CHANGED();
+
+ rs.is_bad_exit = 1;
+ ASSERT_CHANGED();
+
+ rs.is_hs_dir = 1;
+ ASSERT_CHANGED();
+
+ rs.is_v2_dir = 1;
+ ASSERT_CHANGED();
+
+ rs.is_staledesc = 1;
+ ASSERT_CHANGED();
+
+ // Setting this to zero crashes us with an assertion failure in
+ // routerstatus_format_entry() if we don't have a descriptor.
+ rs.has_bandwidth = 0;
+ ASSERT_CHANGED_NO_FORMAT();
+
+ // Does not actually matter; not visible to controller.
+ rs.has_exitsummary = 1;
+ ASSERT_SAME();
+
+ // Does not actually matter; not visible to the controller.
+ rs.bw_is_unmeasured = 1;
+ ASSERT_SAME();
+
+ rs.bandwidth_kb = 2000;
+ ASSERT_CHANGED();
+
+ // not visible to the controller.
+ rs.has_guardfraction = 1;
+ rs.guardfraction_percentage = 22;
+ ASSERT_SAME();
+
+ // not visible to the controller.
+ rs_orig.has_guardfraction = 1;
+ rs_orig.guardfraction_percentage = 20;
+ COPY();
+ rs.guardfraction_percentage = 25;
+ ASSERT_SAME();
+
+ // not visible to the controller.
+ rs.exitsummary = (char*)"accept 1-2";
+ ASSERT_SAME();
+
+ done:
+#undef COPY
+#undef ASSERT_SAME
+#undef ASSERT_CHANGED
+ tor_free(fmt_orig);
+ tor_free(fmt);
+ return;
+}
+
#define NODE(name, flags) \
{ #name, test_nodelist_##name, (flags), NULL, NULL }
@@ -239,6 +1430,18 @@ struct testcase_t nodelist_tests[] = {
NODE(node_get_verbose_nickname_not_named, TT_FORK),
NODE(node_is_dir, TT_FORK),
NODE(ed_id, TT_FORK),
+ NODE(nodefamily, TT_FORK),
+ NODE(nodefamily_parse_err, TT_FORK),
+ NODE(nodefamily_lookup, TT_FORK),
+ NODE(nickname_matches, 0),
+ NODE(node_nodefamily, TT_FORK),
+ NODE(nodefamily_canonicalize, 0),
+ NODE(format_node_description, 0),
+ NODE(router_describe, 0),
+ NODE(node_describe, 0),
+ NODE(routerstatus_describe, 0),
+ NODE(extend_info_describe, 0),
+ NODE(router_get_verbose_nickname, 0),
+ NODE(routerstatus_has_visibly_changed, 0),
END_OF_TESTCASES
};
-
diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c
index 68b6927f56..a1508d0afc 100644
--- a/src/test/test_ntor_cl.c
+++ b/src/test/test_ntor_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_oom.c b/src/test/test_oom.c
index b813fa43a3..51c237ec2e 100644
--- a/src/test/test_oom.c
+++ b/src/test/test_oom.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for OOM handling logic */
@@ -8,7 +8,7 @@
#define CIRCUITLIST_PRIVATE
#define CONNECTION_PRIVATE
#include "core/or/or.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "core/or/circuitlist.h"
#include "lib/evloop/compat_libevent.h"
#include "core/mainloop/connection.h"
diff --git a/src/test/test_oos.c b/src/test/test_oos.c
index 815feda7ce..f8c712a6b6 100644
--- a/src/test/test_oos.c
+++ b/src/test/test_oos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for OOS handler */
diff --git a/src/test/test_options.c b/src/test/test_options.c
index 0e52967a23..714ee4767f 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -1,19 +1,29 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
+#define RELAY_CONFIG_PRIVATE
+#define LOG_PRIVATE
+#define ROUTERSET_PRIVATE
#include "core/or/or.h"
-#include "app/config/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "app/config/config.h"
+#include "feature/dirauth/dirauth_config.h"
+#include "feature/dirauth/dirauth_options_st.h"
+#include "feature/dirauth/dirauth_sys.h"
+#include "feature/relay/relay_config.h"
#include "test/test.h"
#include "lib/geoip/geoip.h"
-#define ROUTERSET_PRIVATE
#include "feature/nodelist/routerset.h"
#include "core/mainloop/mainloop.h"
+#include "app/main/subsysmgr.h"
#include "test/log_test_helpers.h"
+#include "test/resolve_test_helpers.h"
+#include "lib/crypt_ops/crypto_options_st.h"
+#include "lib/crypt_ops/crypto_sys.h"
#include "lib/sandbox/sandbox.h"
#include "lib/memarea/memarea.h"
@@ -21,24 +31,23 @@
#include "lib/encoding/confline.h"
#include "core/or/policies.h"
#include "test/test_helpers.h"
+#include "test/opts_test_helpers.h"
#include "lib/net/resolve.h"
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
-#define NS_MODULE test_options
-
typedef struct {
int severity;
- uint32_t domain;
+ log_domain_mask_t domain;
char *msg;
} logmsg_t;
static smartlist_t *messages = NULL;
static void
-log_cback(int severity, uint32_t domain, const char *msg)
+log_cback(int severity, log_domain_mask_t domain, const char *msg)
{
logmsg_t *x = tor_malloc(sizeof(*x));
x->severity = severity;
@@ -54,9 +63,9 @@ setup_log_callback(void)
{
log_severity_list_t lst;
memset(&lst, 0, sizeof(lst));
- lst.masks[LOG_ERR - LOG_ERR] = ~0;
- lst.masks[LOG_WARN - LOG_ERR] = ~0;
- lst.masks[LOG_NOTICE - LOG_ERR] = ~0;
+ lst.masks[SEVERITY_MASK_IDX(LOG_ERR)] = LD_ALL_DOMAINS;
+ lst.masks[SEVERITY_MASK_IDX(LOG_WARN)] = LD_ALL_DOMAINS;
+ lst.masks[SEVERITY_MASK_IDX(LOG_NOTICE)] = LD_ALL_DOMAINS;
add_callback_log(&lst, log_cback);
mark_logs_temp();
}
@@ -90,16 +99,57 @@ clear_log_messages(void)
messages = NULL;
}
-#define setup_options(opt,dflt) \
+#define setup_options(opt) \
do { \
opt = options_new(); \
opt->command = CMD_RUN_TOR; \
options_init(opt); \
- \
- dflt = config_dup(&options_format, opt); \
- clear_log_messages(); \
} while (0)
+#ifdef COCCI
+
+#define ENABLE_AUTHORITY_MIN ""
+#define ENABLE_AUTHORITY_V3_MIN ""
+#define ENABLE_AUTHORITY_BRIDGE_MIN ""
+#define AUTHORITY_OPT_REQ_ ""
+#define ENABLE_AUTHORITY ""
+#define ENABLE_AUTHORITY_V3 ""
+#define ENABLE_AUTHORITY_BRIDGE ""
+
+#else /* !defined(COCCI) */
+
+#define ENABLE_AUTHORITY_MIN \
+ "AuthoritativeDirectory 1\n"
+
+#define ENABLE_AUTHORITY_V3_MIN \
+ ENABLE_AUTHORITY_MIN \
+ "V3AuthoritativeDir 1\n"
+
+#define ENABLE_AUTHORITY_BRIDGE_MIN \
+ ENABLE_AUTHORITY_MIN \
+ "BridgeAuthoritativeDir 1\n"
+
+#define AUTHORITY_OPT_REQ_ \
+ "Address 192.0.2.111\n" \
+ "ContactInfo a@example.org\n" \
+ "DirPort 1025\n" \
+ "ORPort 1026\n"
+
+/* Not actually valid: requires v3 / bridge */
+#define ENABLE_AUTHORITY \
+ ENABLE_AUTHORITY_MIN \
+ AUTHORITY_OPT_REQ_
+
+#define ENABLE_AUTHORITY_V3 \
+ ENABLE_AUTHORITY_V3_MIN \
+ AUTHORITY_OPT_REQ_
+
+#define ENABLE_AUTHORITY_BRIDGE \
+ ENABLE_AUTHORITY_BRIDGE_MIN \
+ AUTHORITY_OPT_REQ_
+
+#endif /* defined(COCCI) */
+
#define VALID_DIR_AUTH "DirAuthority dizum orport=443 v3ident=E8A9C45" \
"EDE6D711294FADF8E7951F4DE6CA56B58 194.109.206.212:80 7EA6 EAD6 FD83" \
" 083C 538F 4403 8BBF A077 587D D755\n"
@@ -179,12 +229,11 @@ test_options_validate_impl(const char *configuration,
int phase)
{
or_options_t *opt=NULL;
- or_options_t *dflt;
config_line_t *cl=NULL;
char *msg=NULL;
int r;
- setup_options(opt, dflt);
+ setup_options(opt);
r = config_get_lines(configuration, &cl, 1);
if (phase == PH_GETLINES) {
@@ -196,7 +245,7 @@ test_options_validate_impl(const char *configuration,
if (r)
goto done;
- r = config_assign(&options_format, opt, cl, 0, &msg);
+ r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
if (phase == PH_ASSIGN) {
if (test_options_checkmsgs(configuration, expect_errmsg,
expect_log_severity,
@@ -207,7 +256,7 @@ test_options_validate_impl(const char *configuration,
if (r)
goto done;
- r = options_validate(NULL, opt, dflt, 0, &msg);
+ r = options_validate(NULL, opt, &msg);
if (phase == PH_VALIDATE) {
if (test_options_checkmsgs(configuration, expect_errmsg,
expect_log_severity,
@@ -221,7 +270,6 @@ test_options_validate_impl(const char *configuration,
policies_free_all();
config_free_lines(cl);
or_options_free(opt);
- or_options_free(dflt);
tor_free(msg);
clear_log_messages();
}
@@ -241,6 +289,7 @@ test_options_validate(void *arg)
(void)arg;
setup_log_callback();
sandbox_disable_getaddrinfo_cache();
+ mock_hostname_resolver();
WANT_ERR("ExtORPort 500000", "Invalid ExtORPort", PH_VALIDATE);
@@ -258,14 +307,10 @@ test_options_validate(void *arg)
WANT_ERR("BridgeRelay 1\nDirCache 0",
"We're a bridge but DirCache is disabled.", PH_VALIDATE);
- WANT_ERR_LOG("HeartbeatPeriod 21 snarks",
- "Interval 'HeartbeatPeriod 21 snarks' is malformed or"
- " out of bounds.", LOG_WARN, "Unknown unit 'snarks'.",
- PH_ASSIGN);
- WANT_ERR_LOG("LogTimeGranularity 21 snarks",
- "Msec interval 'LogTimeGranularity 21 snarks' is malformed or"
- " out of bounds.", LOG_WARN, "Unknown unit 'snarks'.",
- PH_ASSIGN);
+ WANT_ERR("HeartbeatPeriod 21 snarks",
+ "Unknown unit in 21 snarks", PH_ASSIGN);
+ WANT_ERR("LogTimeGranularity 21 snarks",
+ "Unknown unit in 21 snarks", PH_ASSIGN);
OK("HeartbeatPeriod 1 hour", PH_VALIDATE);
OK("LogTimeGranularity 100 milliseconds", PH_VALIDATE);
@@ -278,6 +323,7 @@ test_options_validate(void *arg)
close_temp_logs();
clear_log_messages();
+ unmock_hostname_resolver();
return;
}
@@ -287,20 +333,18 @@ test_have_enough_mem_for_dircache(void *arg)
{
(void)arg;
or_options_t *opt=NULL;
- or_options_t *dflt=NULL;
config_line_t *cl=NULL;
char *msg=NULL;
int r;
const char *configuration = "ORPort 8080\nDirCache 1", *expect_errmsg;
- setup_options(opt, dflt);
+ setup_options(opt);
setup_log_callback();
- (void)dflt;
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&options_format, opt, cl, 0, &msg);
+ r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
tt_int_op(r, OP_EQ, 0);
/* 300 MB RAM available, DirCache enabled */
@@ -323,7 +367,7 @@ test_have_enough_mem_for_dircache(void *arg)
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&options_format, opt, cl, 0, &msg);
+ r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
tt_int_op(r, OP_EQ, 0);
/* 300 MB RAM available, DirCache enabled, Bridge */
@@ -346,7 +390,7 @@ test_have_enough_mem_for_dircache(void *arg)
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
- r = config_assign(&options_format, opt, cl, 0, &msg);
+ r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
tt_int_op(r, OP_EQ, 0);
/* 200 MB RAM available, DirCache disabled */
@@ -369,7 +413,6 @@ test_have_enough_mem_for_dircache(void *arg)
done:
if (msg)
tor_free(msg);
- or_options_free(dflt);
or_options_free(opt);
config_free_lines(cl);
return;
@@ -383,33 +426,8 @@ fixed_get_uname(void)
return fixed_get_uname_result;
}
-#define TEST_OPTIONS_OLD_VALUES "TestingV3AuthInitialVotingInterval 1800\n" \
- "ClientBootstrapConsensusMaxInProgressTries 3\n" \
- "TestingV3AuthInitialVoteDelay 300\n" \
- "TestingV3AuthInitialDistDelay 300\n" \
- "TestingClientMaxIntervalWithoutRequest 600\n" \
- "TestingDirConnectionMaxStall 600\n" \
-
-#define TEST_OPTIONS_DEFAULT_VALUES TEST_OPTIONS_OLD_VALUES \
- "MaxClientCircuitsPending 1\n" \
- "RendPostPeriod 1000\n" \
- "KeepAlivePeriod 1\n" \
- "ConnLimit 1\n" \
- "V3AuthVotingInterval 300\n" \
- "V3AuthVoteDelay 20\n" \
- "V3AuthDistDelay 20\n" \
- "V3AuthNIntervalsValid 3\n" \
- "ClientUseIPv4 1\n" \
- "VirtualAddrNetworkIPv4 127.192.0.0/10\n" \
- "VirtualAddrNetworkIPv6 [FE80::]/10\n" \
- "UseEntryGuards 1\n" \
- "Schedulers Vanilla\n" \
- "ClientDNSRejectInternalAddresses 1\n"
-
typedef struct {
- or_options_t *old_opt;
or_options_t *opt;
- or_options_t *def_opt;
} options_test_data_t;
static void free_options_test_data(options_test_data_t *td);
@@ -422,17 +440,12 @@ get_options_test_data(const char *conf)
config_line_t *cl=NULL;
options_test_data_t *result = tor_malloc(sizeof(options_test_data_t));
result->opt = options_new();
- result->old_opt = options_new();
- result->def_opt = options_new();
- // XXX: Really, all of these options should be set to defaults
- // with options_init(), but about a dozen tests break when I do that.
- // Being kinda lame and just fixing the immedate breakage for now..
- result->opt->ConnectionPadding = -1; // default must be "auto"
+ options_init(result->opt);
rv = config_get_lines(conf, &cl, 1);
tt_int_op(rv, OP_EQ, 0);
- rv = config_assign(&options_format, result->opt, cl, 0, &msg);
+ rv = config_assign(get_options_mgr(), result->opt, cl, 0, &msg);
if (msg) {
/* Display the parse error message by comparing it with an empty string */
tt_str_op(msg, OP_EQ, "");
@@ -441,13 +454,7 @@ get_options_test_data(const char *conf)
config_free_lines(cl);
result->opt->LogTimeGranularity = 1;
result->opt->TokenBucketRefillInterval = 1;
- rv = config_get_lines(TEST_OPTIONS_OLD_VALUES, &cl, 1);
- tt_int_op(rv, OP_EQ, 0);
- rv = config_assign(&options_format, result->def_opt, cl, 0, &msg);
- if (msg) {
- /* Display the parse error message by comparing it with an empty string */
- tt_str_op(msg, OP_EQ, "");
- }
+ rv = config_get_lines("", &cl, 1);
tt_int_op(rv, OP_EQ, 0);
done:
@@ -466,9 +473,7 @@ static void
free_options_test_data(options_test_data_t *td)
{
if (!td) return;
- or_options_free(td->old_opt);
or_options_free(td->opt);
- or_options_free(td->def_opt);
tor_free(td);
}
@@ -491,7 +496,7 @@ test_options_validate__uname_for_server(void *ignored)
MOCK(get_uname, fixed_get_uname);
fixed_get_uname_result = "Windows 95";
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("Tor is running as a server, but you"
" are running Windows 95; this probably won't work. See https://www"
".torproject.org/docs/faq.html#BestOSForRelay for details.\n");
@@ -499,7 +504,7 @@ test_options_validate__uname_for_server(void *ignored)
fixed_get_uname_result = "Windows 98";
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("Tor is running as a server, but you"
" are running Windows 98; this probably won't work. See https://www"
".torproject.org/docs/faq.html#BestOSForRelay for details.\n");
@@ -507,7 +512,7 @@ test_options_validate__uname_for_server(void *ignored)
fixed_get_uname_result = "Windows Me";
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("Tor is running as a server, but you"
" are running Windows Me; this probably won't work. See https://www"
".torproject.org/docs/faq.html#BestOSForRelay for details.\n");
@@ -515,8 +520,8 @@ test_options_validate__uname_for_server(void *ignored)
fixed_get_uname_result = "Windows 2000";
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- expect_no_log_entry();
+ options_validate(NULL, tdata->opt, &msg);
+ expect_no_log_msg("Tor is running as a server, but you ");
tor_free(msg);
done:
@@ -539,7 +544,7 @@ test_options_validate__outbound_addresses(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"OutboundBindAddress xxyy!!!sdfaf");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Multiple outbound bind addresses configured: "
"xxyy!!!sdfaf");
@@ -576,7 +581,7 @@ test_options_validate__data_directory(void *ignored)
"ONGLONGlongreallylongLONG"
"LONG"); // 440 characters
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Invalid DataDirectory");
@@ -594,7 +599,7 @@ test_options_validate__nickname(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"Nickname ThisNickNameIsABitTooLong");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Nickname 'ThisNickNameIsABitTooLong', nicknames must be between "
@@ -604,16 +609,14 @@ test_options_validate__nickname(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("Nickname AMoreValidNick");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("DataDirectory /tmp/somewhere");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
done:
free_options_test_data(tdata);
@@ -631,8 +634,8 @@ test_options_validate__contactinfo(void *ignored)
setup_capture_of_logs(LOG_DEBUG);
tdata->opt->ContactInfo = NULL;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"Your ContactInfo config option is not set. Please strongly "
"consider setting it, so we can contact you if your relay is "
@@ -645,8 +648,8 @@ test_options_validate__contactinfo(void *ignored)
tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"ContactInfo hella@example.org");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"Your ContactInfo config option is not set. Please strongly "
"consider setting it, so we can contact you if your relay is "
@@ -673,50 +676,53 @@ test_options_validate__logs(void *ignored)
tdata->opt->Logs = NULL;
tdata->opt->RunAsDaemon = 0;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_str_op(tdata->opt->Logs->key, OP_EQ, "Log");
- tt_str_op(tdata->opt->Logs->value, OP_EQ, "notice stdout");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_assert(!tdata->opt->Logs);
tor_free(msg);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, 0);
free_options_test_data(tdata);
tdata = get_options_test_data("");
tdata->opt->Logs = NULL;
tdata->opt->RunAsDaemon = 0;
quiet_level = 1;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_str_op(tdata->opt->Logs->key, OP_EQ, "Log");
- tt_str_op(tdata->opt->Logs->value, OP_EQ, "warn stdout");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_assert(!tdata->opt->Logs);
tor_free(msg);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, 0);
free_options_test_data(tdata);
tdata = get_options_test_data("");
tdata->opt->Logs = NULL;
tdata->opt->RunAsDaemon = 0;
quiet_level = 2;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_assert(!tdata->opt->Logs);
tor_free(msg);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, 0);
free_options_test_data(tdata);
tdata = get_options_test_data("");
tdata->opt->Logs = NULL;
tdata->opt->RunAsDaemon = 0;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 1, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_assert(!tdata->opt->Logs);
tor_free(msg);
- tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(ret, OP_EQ, 0);
free_options_test_data(tdata);
tdata = get_options_test_data("");
tdata->opt->Logs = NULL;
tdata->opt->RunAsDaemon = 1;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_assert(!tdata->opt->Logs);
tor_free(msg);
+#ifdef _WIN32
+ /* Can't RunAsDaemon on Windows. */
tt_int_op(ret, OP_EQ, -1);
+#else
+ tt_int_op(ret, OP_EQ, 0);
+#endif /* defined(_WIN32) */
free_options_test_data(tdata);
tdata = get_options_test_data("");
@@ -724,7 +730,7 @@ test_options_validate__logs(void *ignored)
config_line_t *cl=NULL;
config_get_lines("Log foo", &cl, 1);
tdata->opt->Logs = cl;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op((intptr_t)tdata->opt->Logs, OP_EQ, (intptr_t)cl);
tt_int_op(ret, OP_EQ, -1);
@@ -752,13 +758,14 @@ test_options_validate__authdir(void *ignored)
char *msg;
setup_capture_of_logs(LOG_INFO);
options_test_data_t *tdata = get_options_test_data(
- "AuthoritativeDirectory 1\n"
+ ENABLE_AUTHORITY_V3_MIN
"Address this.should.not!exist!.example.org");
+ const dirauth_options_t *da_opt;
sandbox_disable_getaddrinfo_cache();
MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
UNMOCK(tor_addr_lookup);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Failed to resolve/guess local address. See logs for"
@@ -768,246 +775,217 @@ test_options_validate__authdir(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3_MIN
"Address 100.200.10.1");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Authoritative directory servers must set "
"ContactInfo");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3_MIN
"Address 100.200.10.1\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Authoritative directory servers must set ContactInfo");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_MIN
"Address 100.200.10.1\n"
"TestingTorNetwork 1\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "AuthoritativeDir is set, but none of (Bridge/V3)"
"AuthoritativeDir is set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "AuthoritativeDir is set, but none of (Bridge/V3)"
"AuthoritativeDir is set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "RecommendedVersions 1.2, 3.14\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "RecommendedVersions 1.2, 3.14\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_str_op(tdata->opt->RecommendedClientVersions->value, OP_EQ, "1.2, 3.14");
- tt_str_op(tdata->opt->RecommendedServerVersions->value, OP_EQ, "1.2, 3.14");
+ options_validate(NULL, tdata->opt, &msg);
+ da_opt = get_dirauth_options(tdata->opt);
+ tt_str_op(da_opt->RecommendedClientVersions->value, OP_EQ, "1.2, 3.14");
+ tt_str_op(da_opt->RecommendedServerVersions->value, OP_EQ, "1.2, 3.14");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"RecommendedVersions 1.2, 3.14\n"
"RecommendedClientVersions 25\n"
- "RecommendedServerVersions 4.18\n"
- "ContactInfo hello@hello.com\n");
+ "RecommendedServerVersions 4.18\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_str_op(tdata->opt->RecommendedClientVersions->value, OP_EQ, "25");
- tt_str_op(tdata->opt->RecommendedServerVersions->value, OP_EQ, "4.18");
+ options_validate(NULL, tdata->opt, &msg);
+ da_opt = get_dirauth_options(tdata->opt);
+ tt_str_op(da_opt->RecommendedClientVersions->value, OP_EQ, "25");
+ tt_str_op(da_opt->RecommendedServerVersions->value, OP_EQ, "4.18");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY
"VersioningAuthoritativeDirectory 1\n"
"RecommendedVersions 1.2, 3.14\n"
"RecommendedClientVersions 25\n"
- "RecommendedServerVersions 4.18\n"
- "ContactInfo hello@hello.com\n");
+ "RecommendedServerVersions 4.18\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
+ da_opt = get_dirauth_options(tdata->opt);
tt_str_op(msg, OP_EQ, "AuthoritativeDir is set, but none of (Bridge/V3)"
"AuthoritativeDir is set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"VersioningAuthoritativeDirectory 1\n"
- "RecommendedServerVersions 4.18\n"
- "ContactInfo hello@hello.com\n");
+ "RecommendedServerVersions 4.18\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
+ da_opt = get_dirauth_options(tdata->opt);
tt_str_op(msg, OP_EQ, "Versioning authoritative dir servers must set "
"Recommended*Versions.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"VersioningAuthoritativeDirectory 1\n"
- "RecommendedClientVersions 4.18\n"
- "ContactInfo hello@hello.com\n");
+ "RecommendedClientVersions 4.18\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
+ da_opt = get_dirauth_options(tdata->opt);
tt_str_op(msg, OP_EQ, "Versioning authoritative dir servers must set "
"Recommended*Versions.");
tor_free(msg);
+ da_opt = NULL;
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "UseEntryGuards 1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "UseEntryGuards 1\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("Authoritative directory servers "
"can't set UseEntryGuards. Disabling.\n");
tt_int_op(tdata->opt->UseEntryGuards, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "V3AuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "DownloadExtraInfo 0\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("Authoritative directories always try"
" to download extra-info documents. Setting DownloadExtraInfo.\n");
tt_int_op(tdata->opt->DownloadExtraInfo, OP_EQ, 1);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "DownloadExtraInfo 1\n"
- "V3AuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "V3BandwidthsFile non-existent-file\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- expect_no_log_msg("Authoritative directories always try"
- " to download extra-info documents. Setting DownloadExtraInfo.\n");
- tt_int_op(tdata->opt->DownloadExtraInfo, OP_EQ, 1);
+ options_validate(NULL, tdata->opt, &msg);
+ expect_log_msg("Can't open bandwidth file at configured location: "
+ "non-existent-file\n");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "GuardfractionFile non-existent-file\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_str_op(msg, OP_EQ, "AuthoritativeDir is set, but none of (Bridge/V3)"
- "AuthoritativeDir is set.");
+ options_validate(NULL, tdata->opt, &msg);
+ expect_log_msg("Cannot open guardfraction file 'non-existent-file'. "
+ "Failing.\n");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3_MIN
"Address 100.200.10.1\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "V3BandwidthsFile non-existent-file\n");
+ "ORPort 2000\n"
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Running as authoritative directory, but no DirPort set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_BRIDGE_MIN
"Address 100.200.10.1\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "V3BandwidthsFile non-existent-file\n");
+ "ORPort 2000\n"
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
- options_validate(NULL, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Running as authoritative directory, but no DirPort set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3_MIN
"Address 100.200.10.1\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "GuardfractionFile non-existent-file\n");
+ "DirPort 999\n"
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
- "Running as authoritative directory, but no DirPort set.");
+ "Running as authoritative directory, but no ORPort set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
+ tdata = get_options_test_data(ENABLE_AUTHORITY_BRIDGE_MIN
"Address 100.200.10.1\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "GuardfractionFile non-existent-file\n");
+ "DirPort 999\n"
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
- options_validate(NULL, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
- "Running as authoritative directory, but no DirPort set.");
+ "Running as authoritative directory, but no ORPort set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "ClientOnly 1\n");
+ /* We have to call the dirauth-specific function, and fake port parsing,
+ * to hit this case */
+ tdata->opt->DirPort_set = 1;
+ tdata->opt->ORPort_set = 1;
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate_dirauth_mode(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ,
- "Running as authoritative directory, but no DirPort set.");
+ tt_str_op(msg, OP_EQ, "Running as authoritative directory, "
+ "but ClientOnly also set.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "DirPort 999\n"
- "BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n");
+ tdata = get_options_test_data(ENABLE_AUTHORITY_BRIDGE
+ "ClientOnly 1\n");
+ /* We have to call the dirauth-specific function, and fake port parsing,
+ * to hit this case */
+ tdata->opt->DirPort_set = 1;
+ tdata->opt->ORPort_set = 1;
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate_dirauth_mode(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ,
- "Running as authoritative directory, but no ORPort set.");
+ tt_str_op(msg, OP_EQ, "Running as authoritative directory, "
+ "but ClientOnly also set.");
tor_free(msg);
- // TODO: This case can't be reached, since clientonly is used to
- // check when parsing port lines as well.
- /* free_options_test_data(tdata); */
- /* tdata = get_options_test_data("AuthoritativeDirectory 1\n" */
- /* "Address 100.200.10.1\n" */
- /* "DirPort 999\n" */
- /* "ORPort 888\n" */
- /* "ClientOnly 1\n" */
- /* "BridgeAuthoritativeDir 1\n" */
- /* "ContactInfo hello@hello.com\n" ); */
- /* mock_clean_saved_logs(); */
- /* ret = options_validate(tdata->old_opt, tdata->opt, */
- /* tdata->def_opt, 0, &msg); */
- /* tt_int_op(ret, OP_EQ, -1); */
- /* tt_str_op(msg, OP_EQ, "Running as authoritative directory, " */
- /* "but ClientOnly also set."); */
-
done:
teardown_capture_of_logs();
// sandbox_free_getaddrinfo_cache();
@@ -1020,6 +998,7 @@ test_options_validate__relay_with_hidden_services(void *ignored)
{
(void)ignored;
char *msg;
+ int ret;
setup_capture_of_logs(LOG_DEBUG);
options_test_data_t *tdata = get_options_test_data(
"ORPort 127.0.0.1:5555\n"
@@ -1028,12 +1007,13 @@ test_options_validate__relay_with_hidden_services(void *ignored)
"HiddenServicePort 80 127.0.0.1:8080\n"
);
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"Tor is currently configured as a relay and a hidden service. "
"That's not very secure: you should probably run your hidden servi"
"ce in a separate Tor process, at least -- see "
- "https://trac.torproject.org/8742\n");
+ "https://bugs.torproject.org/tpo/core/tor/8742.\n");
done:
teardown_capture_of_logs();
@@ -1041,27 +1021,25 @@ test_options_validate__relay_with_hidden_services(void *ignored)
tor_free(msg);
}
-// TODO: it doesn't seem possible to hit the case of having no port lines at
-// all, since there will be a default created for SocksPort
-/* static void */
-/* test_options_validate__ports(void *ignored) */
-/* { */
-/* (void)ignored; */
-/* int ret; */
-/* char *msg; */
-/* setup_capture_of_logs(LOG_WARN); */
-/* options_test_data_t *tdata = get_options_test_data(""); */
-/* ret = options_validate(tdata->old_opt, tdata->opt, */
-/* tdata->def_opt, 0, &msg); */
-/* expect_log_msg("SocksPort, TransPort, NATDPort, DNSPort, and ORPort " */
-/* "are all undefined, and there aren't any hidden services " */
-/* "configured. " */
-/* " Tor will still run, but probably won't do anything.\n"); */
-/* done: */
-/* teardown_capture_of_logs(); */
-/* free_options_test_data(tdata); */
-/* tor_free(msg); */
-/* } */
+static void
+test_options_validate__listen_ports(void *ignored)
+{
+ (void)ignored;
+ int ret;
+ char *msg;
+ setup_capture_of_logs(LOG_WARN);
+ options_test_data_t *tdata = get_options_test_data("SOCKSPort 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ expect_log_msg("SocksPort, TransPort, NATDPort, DNSPort, and ORPort "
+ "are all undefined, and there aren't any hidden services "
+ "configured. "
+ " Tor will still run, but probably won't do anything.\n");
+ done:
+ teardown_capture_of_logs();
+ free_options_test_data(tdata);
+ tor_free(msg);
+}
static void
test_options_validate__transproxy(void *ignored)
@@ -1075,31 +1053,31 @@ test_options_validate__transproxy(void *ignored)
// Test default trans proxy
tdata = get_options_test_data("TransProxyType default\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->TransProxyType_parsed, OP_EQ, TPT_DEFAULT);
tor_free(msg);
// Test pf-divert trans proxy
free_options_test_data(tdata);
tdata = get_options_test_data("TransProxyType pf-divert\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
-#if !defined(OpenBSD) && !defined( DARWIN )
+#if !defined(OpenBSD) && !defined(DARWIN)
tt_str_op(msg, OP_EQ,
"pf-divert is a OpenBSD-specific and OS X/Darwin-specific feature.");
#else
tt_int_op(tdata->opt->TransProxyType_parsed, OP_EQ, TPT_PF_DIVERT);
tt_str_op(msg, OP_EQ, "Cannot use TransProxyType without "
"any valid TransPort.");
-#endif /* !defined(OpenBSD) && !defined( DARWIN ) */
+#endif /* !defined(OpenBSD) && !defined(DARWIN) */
tor_free(msg);
// Test tproxy trans proxy
free_options_test_data(tdata);
tdata = get_options_test_data("TransProxyType tproxy\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
#if !defined(__linux__)
@@ -1114,7 +1092,7 @@ test_options_validate__transproxy(void *ignored)
// Test ipfw trans proxy
free_options_test_data(tdata);
tdata = get_options_test_data("TransProxyType ipfw\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
#ifndef KERNEL_MAY_SUPPORT_IPFW
@@ -1130,7 +1108,7 @@ test_options_validate__transproxy(void *ignored)
// Test unknown trans proxy
free_options_test_data(tdata);
tdata = get_options_test_data("TransProxyType non-existent\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Unrecognized value for TransProxyType");
tor_free(msg);
@@ -1142,39 +1120,35 @@ test_options_validate__transproxy(void *ignored)
#if defined(__linux__)
tdata = get_options_test_data("TransProxyType tproxy\n"
"TransPort 127.0.0.1:123\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
#elif defined(KERNEL_MAY_SUPPORT_IPFW)
tdata = get_options_test_data("TransProxyType ipfw\n"
"TransPort 127.0.0.1:123\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
#elif defined(OpenBSD)
tdata = get_options_test_data("TransProxyType pf-divert\n"
"TransPort 127.0.0.1:123\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
#elif defined(__NetBSD__)
tdata = get_options_test_data("TransProxyType default\n"
"TransPort 127.0.0.1:123\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
#endif /* defined(__linux__) || ... */
// Assert that a test has run for some TransProxyType
tt_assert(tdata);
-#else /* !(defined(USE_TRANSPARENT)) */
+#else /* !defined(USE_TRANSPARENT) */
tdata = get_options_test_data("TransPort 127.0.0.1:555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TransPort is disabled in this build.");
tor_free(msg);
@@ -1185,13 +1159,14 @@ test_options_validate__transproxy(void *ignored)
tor_free(msg);
}
-NS_DECL(country_t, geoip_get_country, (const char *country));
+static country_t opt_tests_geoip_get_country(const char *country);
+ATTR_UNUSED static int opt_tests_geoip_get_country_called = 0;
static country_t
-NS(geoip_get_country)(const char *countrycode)
+opt_tests_geoip_get_country(const char *countrycode)
{
(void)countrycode;
- CALLED(geoip_get_country)++;
+ opt_tests_geoip_get_country_called++;
return 1;
}
@@ -1201,7 +1176,8 @@ test_options_validate__exclude_nodes(void *ignored)
{
(void)ignored;
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_get_country,
+ opt_tests_geoip_get_country);
int ret;
char *msg;
@@ -1209,8 +1185,8 @@ test_options_validate__exclude_nodes(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"ExcludeExitNodes {us}\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(tdata->opt->ExcludeExitNodesUnion_->list), OP_EQ, 1);
tt_str_op((char *)
(smartlist_get(tdata->opt->ExcludeExitNodesUnion_->list, 0)),
@@ -1219,8 +1195,8 @@ test_options_validate__exclude_nodes(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ExcludeNodes {cn}\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(tdata->opt->ExcludeExitNodesUnion_->list), OP_EQ, 1);
tt_str_op((char *)
(smartlist_get(tdata->opt->ExcludeExitNodesUnion_->list, 0)),
@@ -1230,8 +1206,8 @@ test_options_validate__exclude_nodes(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ExcludeNodes {cn}\n"
"ExcludeExitNodes {us} {cn}\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(tdata->opt->ExcludeExitNodesUnion_->list), OP_EQ, 2);
tt_str_op((char *)
(smartlist_get(tdata->opt->ExcludeExitNodesUnion_->list, 0)),
@@ -1245,8 +1221,8 @@ test_options_validate__exclude_nodes(void *ignored)
tdata = get_options_test_data("ExcludeNodes {cn}\n"
"StrictNodes 1\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"You have asked to exclude certain relays from all positions "
"in your circuits. Expect hidden services and other Tor "
@@ -1256,8 +1232,8 @@ test_options_validate__exclude_nodes(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ExcludeNodes {cn}\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"You have asked to exclude certain relays from all positions "
"in your circuits. Expect hidden services and other Tor "
@@ -1265,7 +1241,7 @@ test_options_validate__exclude_nodes(void *ignored)
tor_free(msg);
done:
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_get_country);
teardown_capture_of_logs();
free_options_test_data(tdata);
tor_free(msg);
@@ -1281,8 +1257,8 @@ test_options_validate__node_families(void *ignored)
"NodeFamily flux, flax\n"
"NodeFamily somewhere\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(tdata->opt->NodeFamilySets);
tt_int_op(smartlist_len(tdata->opt->NodeFamilySets), OP_EQ, 2);
tt_str_op((char *)(smartlist_get(
@@ -1299,15 +1275,15 @@ test_options_validate__node_families(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(!tdata->opt->NodeFamilySets);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("NodeFamily !flux\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_assert(tdata->opt->NodeFamilySets);
tt_int_op(smartlist_len(tdata->opt->NodeFamilySets), OP_EQ, 0);
@@ -1327,14 +1303,14 @@ test_options_validate__token_bucket(void *ignored)
options_test_data_t *tdata = get_options_test_data("");
tdata->opt->TokenBucketRefillInterval = 0;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"TokenBucketRefillInterval must be between 1 and 1000 inclusive.");
tor_free(msg);
tdata->opt->TokenBucketRefillInterval = 1001;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"TokenBucketRefillInterval must be between 1 and 1000 inclusive.");
@@ -1346,29 +1322,6 @@ test_options_validate__token_bucket(void *ignored)
}
static void
-test_options_validate__recommended_packages(void *ignored)
-{
- (void)ignored;
- int ret;
- char *msg;
- setup_capture_of_logs(LOG_WARN);
- options_test_data_t *tdata = get_options_test_data(
- "RecommendedPackages foo 1.2 http://foo.com sha1=123123123123\n"
- "RecommendedPackages invalid-package-line\n");
-
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- expect_no_log_msg("Invalid RecommendedPackage line "
- "invalid-package-line will be ignored\n");
-
- done:
- escaped(NULL); // This will free the leaking memory from the previous escaped
- teardown_capture_of_logs();
- free_options_test_data(tdata);
- tor_free(msg);
-}
-
-static void
test_options_validate__fetch_dir(void *ignored)
{
(void)ignored;
@@ -1378,7 +1331,7 @@ test_options_validate__fetch_dir(void *ignored)
"FetchDirInfoExtraEarly 1\n"
"FetchDirInfoEarly 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "FetchDirInfoExtraEarly requires that you"
" also set FetchDirInfoEarly");
@@ -1388,10 +1341,8 @@ test_options_validate__fetch_dir(void *ignored)
tdata = get_options_test_data("FetchDirInfoExtraEarly 1\n"
"FetchDirInfoEarly 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_NE, "FetchDirInfoExtraEarly requires that you"
- " also set FetchDirInfoEarly");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
done:
@@ -1408,7 +1359,7 @@ test_options_validate__conn_limit(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"ConnLimit 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
tor_free(msg);
@@ -1416,10 +1367,8 @@ test_options_validate__conn_limit(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ConnLimit 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "MaxClientCircuitsPending must be between 1 and 1024, "
- "but was set to 0");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
done:
@@ -1442,11 +1391,10 @@ test_options_validate__paths_needed(void *ignored)
setup_capture_of_logs(LOG_WARN);
options_test_data_t *tdata = get_options_test_data(
- "PathsNeededToBuildCircuits 0.1\n"
- "ConnLimit 1\n");
+ "PathsNeededToBuildCircuits 0.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(tdata->opt->PathsNeededToBuildCircuits > 0.24 &&
tdata->opt->PathsNeededToBuildCircuits < 0.26);
expect_log_msg("PathsNeededToBuildCircuits is too low. "
@@ -1455,11 +1403,10 @@ test_options_validate__paths_needed(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data("PathsNeededToBuildCircuits 0.99\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("PathsNeededToBuildCircuits 0.99\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(tdata->opt->PathsNeededToBuildCircuits > 0.94 &&
tdata->opt->PathsNeededToBuildCircuits < 0.96);
expect_log_msg("PathsNeededToBuildCircuits is "
@@ -1468,14 +1415,13 @@ test_options_validate__paths_needed(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data("PathsNeededToBuildCircuits 0.91\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("PathsNeededToBuildCircuits 0.91\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(tdata->opt->PathsNeededToBuildCircuits > 0.90 &&
tdata->opt->PathsNeededToBuildCircuits < 0.92);
- expect_no_log_entry();
+ expect_no_log_msg_containing("PathsNeededToBuildCircuits");
tor_free(msg);
done:
@@ -1495,32 +1441,28 @@ test_options_validate__max_client_circuits(void *ignored)
int ret;
char *msg;
options_test_data_t *tdata = get_options_test_data(
- "MaxClientCircuitsPending 0\n"
- "ConnLimit 1\n");
+ "MaxClientCircuitsPending 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "MaxClientCircuitsPending must be between 1 and 1024,"
" but was set to 0");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("MaxClientCircuitsPending 1025\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("MaxClientCircuitsPending 1025\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "MaxClientCircuitsPending must be between 1 and 1024,"
" but was set to 1025");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("MaxClientCircuitsPending 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "KeepalivePeriod option must be positive.");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
done:
@@ -1534,23 +1476,18 @@ test_options_validate__ports(void *ignored)
(void)ignored;
int ret;
char *msg;
- options_test_data_t *tdata = get_options_test_data(
- "FirewallPorts 65537\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ options_test_data_t *tdata = get_options_test_data("FirewallPorts 65537\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Port '65537' out of range in FirewallPorts");
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("FirewallPorts 1\n"
- "LongLivedPorts 124444\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "LongLivedPorts 124444\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Port '124444' out of range in LongLivedPorts");
tor_free(msg);
@@ -1558,11 +1495,9 @@ test_options_validate__ports(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("FirewallPorts 1\n"
"LongLivedPorts 2\n"
- "RejectPlaintextPorts 112233\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "RejectPlaintextPorts 112233\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Port '112233' out of range in RejectPlaintextPorts");
tor_free(msg);
@@ -1571,11 +1506,9 @@ test_options_validate__ports(void *ignored)
tdata = get_options_test_data("FirewallPorts 1\n"
"LongLivedPorts 2\n"
"RejectPlaintextPorts 3\n"
- "WarnPlaintextPorts 65536\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "WarnPlaintextPorts 65536\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Port '65536' out of range in WarnPlaintextPorts");
tor_free(msg);
@@ -1584,13 +1517,10 @@ test_options_validate__ports(void *ignored)
tdata = get_options_test_data("FirewallPorts 1\n"
"LongLivedPorts 2\n"
"RejectPlaintextPorts 3\n"
- "WarnPlaintextPorts 4\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "WarnPlaintextPorts 4\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "KeepalivePeriod option must be positive.");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
done:
@@ -1605,13 +1535,10 @@ test_options_validate__reachable_addresses(void *ignored)
int ret;
char *msg;
setup_capture_of_logs(LOG_NOTICE);
- options_test_data_t *tdata = get_options_test_data(
- "FascistFirewall 1\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ options_test_data_t *tdata = get_options_test_data("FascistFirewall 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_log_msg("Converting FascistFirewall config "
"option to new format: \"ReachableDirAddresses *:80\"\n");
tt_str_op(tdata->opt->ReachableDirAddresses->value, OP_EQ, "*:80");
@@ -1624,13 +1551,17 @@ test_options_validate__reachable_addresses(void *ignored)
mock_clean_saved_logs();
tdata = get_options_test_data("FascistFirewall 1\n"
"ReachableDirAddresses *:81\n"
- "ReachableORAddresses *:444\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
- tdata->opt->FirewallPorts = smartlist_new();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ "ReachableORAddresses *:444\n");
+ tt_assert(tdata->opt->FirewallPorts);
+ SMARTLIST_FOREACH(tdata->opt->FirewallPorts, char *, cp, tor_free(cp));
+ smartlist_clear(tdata->opt->FirewallPorts);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+#if 0
+ /* This does not actually produce any logs, and did not produce any relevant
+ * logs before. */
expect_log_entry();
+#endif
tt_str_op(tdata->opt->ReachableDirAddresses->value, OP_EQ, "*:81");
tt_str_op(tdata->opt->ReachableORAddresses->value, OP_EQ, "*:444");
tor_free(msg);
@@ -1638,12 +1569,10 @@ test_options_validate__reachable_addresses(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
tdata = get_options_test_data("FascistFirewall 1\n"
- "FirewallPort 123\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "FirewallPort 123\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
expect_log_msg("Converting FascistFirewall and "
"FirewallPorts config options to new format: "
"\"ReachableAddresses *:123\"\n");
@@ -1655,25 +1584,25 @@ test_options_validate__reachable_addresses(void *ignored)
tdata = get_options_test_data("FascistFirewall 1\n"
"ReachableAddresses *:82\n"
"ReachableAddresses *:83\n"
- "ReachableAddresses reject *:*\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ReachableAddresses reject *:*\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+#if 0
+ /* This does not actually produce any logs, and did not produce any relevant
+ * logs before. */
expect_log_entry();
+#endif
tt_str_op(tdata->opt->ReachableAddresses->value, OP_EQ, "*:82");
tor_free(msg);
free_options_test_data(tdata);
mock_clean_saved_logs();
tdata = get_options_test_data("FascistFirewall 1\n"
- "ReachableAddresses *:82\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ReachableAddresses *:82\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(tdata->opt->ReachableAddresses->next, OP_EQ, NULL);
tor_free(msg);
@@ -1683,44 +1612,36 @@ test_options_validate__reachable_addresses(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ReachableAddresses *:82\n"
- "ORPort 127.0.0.1:5555\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ORPort 127.0.0.1:5555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, SERVERS_REACHABLE_MSG);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("ReachableORAddresses *:82\n"
- "ORPort 127.0.0.1:5555\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ORPort 127.0.0.1:5555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, SERVERS_REACHABLE_MSG);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("ReachableDirAddresses *:82\n"
- "ORPort 127.0.0.1:5555\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ORPort 127.0.0.1:5555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, SERVERS_REACHABLE_MSG);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("ClientUseIPv4 0\n"
- "ORPort 127.0.0.1:5555\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ORPort 127.0.0.1:5555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, SERVERS_REACHABLE_MSG);
tor_free(msg);
@@ -1728,74 +1649,68 @@ test_options_validate__reachable_addresses(void *ignored)
/* Test IPv4-only clients setting IPv6 preferences */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientUseIPv4 1\n"
+ tdata = get_options_test_data("ClientUseIPv4 1\n"
"ClientUseIPv6 0\n"
"UseBridges 0\n"
"ClientPreferIPv6ORPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientUseIPv4 1\n"
+ tdata = get_options_test_data("ClientUseIPv4 1\n"
"ClientUseIPv6 0\n"
"UseBridges 0\n"
"ClientPreferIPv6DirPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
/* Now test an IPv4/IPv6 client setting IPv6 preferences */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientUseIPv4 1\n"
+ tdata = get_options_test_data("ClientUseIPv4 1\n"
"ClientUseIPv6 1\n"
"ClientPreferIPv6ORPort 1\n"
"ClientPreferIPv6DirPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
/* Now test an IPv6 client setting IPv6 preferences */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientUseIPv6 1\n"
+ tdata = get_options_test_data("ClientUseIPv6 1\n"
"ClientPreferIPv6ORPort 1\n"
"ClientPreferIPv6DirPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
/* And an implicit (IPv4 disabled) IPv6 client setting IPv6 preferences */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientUseIPv4 0\n"
+ tdata = get_options_test_data("ClientUseIPv4 0\n"
"ClientPreferIPv6ORPort 1\n"
"ClientPreferIPv6DirPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
/* And an implicit (bridge) client setting IPv6 preferences */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "UseBridges 1\n"
+ tdata = get_options_test_data("UseBridges 1\n"
"Bridge 127.0.0.1:12345\n"
"ClientPreferIPv6ORPort 1\n"
"ClientPreferIPv6DirPort 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
@@ -1814,76 +1729,68 @@ test_options_validate__use_bridges(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"UseBridges 1\n"
"ClientUseIPv4 1\n"
- "ORPort 127.0.0.1:5555\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "ORPort 127.0.0.1:5555\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Servers must be able to freely connect to the rest of"
" the Internet, so they must not set UseBridges.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("UseBridges 1\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("UseBridges 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_NE, "Servers must be able to freely connect to the rest of"
" the Internet, so they must not set UseBridges.");
tor_free(msg);
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_get_country,
+ opt_tests_geoip_get_country);
free_options_test_data(tdata);
tdata = get_options_test_data("UseBridges 1\n"
- "EntryNodes {cn}\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "EntryNodes {cn}\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "You cannot set both UseBridges and EntryNodes.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "UseBridges 1\n");
+ tdata = get_options_test_data("UseBridges 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"If you set UseBridges, you must specify at least one bridge.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "UseBridges 1\n"
+ tdata = get_options_test_data("UseBridges 1\n"
"Bridge 10.0.0.1\n"
"UseEntryGuards 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Setting UseBridges requires also setting UseEntryGuards.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "UseBridges 1\n"
+ tdata = get_options_test_data("UseBridges 1\n"
"Bridge 10.0.0.1\n"
"Bridge !!!\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Bridge line did not parse. See logs for details.");
tor_free(msg);
done:
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_get_country);
policies_free_all();
free_options_test_data(tdata);
tor_free(msg);
@@ -1895,14 +1802,13 @@ test_options_validate__entry_nodes(void *ignored)
(void)ignored;
int ret;
char *msg;
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_get_country,
+ opt_tests_geoip_get_country);
options_test_data_t *tdata = get_options_test_data(
"EntryNodes {cn}\n"
- "UseEntryGuards 0\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "UseEntryGuards 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"If EntryNodes is set, UseEntryGuards must be enabled.");
@@ -1910,17 +1816,14 @@ test_options_validate__entry_nodes(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("EntryNodes {cn}\n"
- "UseEntryGuards 1\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ "UseEntryGuards 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "KeepalivePeriod option must be positive.");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
done:
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_get_country);
free_options_test_data(tdata);
tor_free(msg);
}
@@ -1931,51 +1834,41 @@ test_options_validate__safe_logging(void *ignored)
(void)ignored;
int ret;
char *msg;
- options_test_data_t *tdata = get_options_test_data(
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ options_test_data_t *tdata = get_options_test_data("SafeLogging 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->SafeLogging_, OP_EQ, SAFELOG_SCRUB_NONE);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("SafeLogging 0\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("SafeLogging 0\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->SafeLogging_, OP_EQ, SAFELOG_SCRUB_NONE);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("SafeLogging Relay\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("SafeLogging Relay\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->SafeLogging_, OP_EQ, SAFELOG_SCRUB_RELAY);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("SafeLogging 1\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("SafeLogging 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->SafeLogging_, OP_EQ, SAFELOG_SCRUB_ALL);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("SafeLogging stuffy\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n");
+ tdata = get_options_test_data("SafeLogging stuffy\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Unrecognized value '\"stuffy\"' in SafeLogging");
tor_free(msg);
@@ -1994,27 +1887,24 @@ test_options_validate__publish_server_descriptor(void *ignored)
char *msg;
setup_capture_of_logs(LOG_WARN);
options_test_data_t *tdata = get_options_test_data(
- "PublishServerDescriptor bridge\n" TEST_OPTIONS_DEFAULT_VALUES
- );
+ "PublishServerDescriptor bridge\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("PublishServerDescriptor humma\n"
- TEST_OPTIONS_DEFAULT_VALUES);
+ tdata = get_options_test_data("PublishServerDescriptor humma\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Unrecognized value in PublishServerDescriptor");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("PublishServerDescriptor bridge, v3\n"
- TEST_OPTIONS_DEFAULT_VALUES);
+ tdata = get_options_test_data("PublishServerDescriptor bridge, v3\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Bridges are not supposed to publish router "
"descriptors to the directory authorities. Please correct your "
@@ -2023,10 +1913,9 @@ test_options_validate__publish_server_descriptor(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("BridgeRelay 1\n"
- "PublishServerDescriptor v3\n"
- TEST_OPTIONS_DEFAULT_VALUES);
+ "PublishServerDescriptor v3\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Bridges are not supposed to publish router "
"descriptors to the directory authorities. Please correct your "
@@ -2034,9 +1923,9 @@ test_options_validate__publish_server_descriptor(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("BridgeRelay 1\n" TEST_OPTIONS_DEFAULT_VALUES);
+ tdata = get_options_test_data("BridgeRelay 1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_NE, "Bridges are not supposed to publish router "
"descriptors to the directory authorities. Please correct your "
@@ -2045,10 +1934,10 @@ test_options_validate__publish_server_descriptor(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("BridgeRelay 1\n"
- "DirPort 999\n" TEST_OPTIONS_DEFAULT_VALUES);
+ "DirPort 999\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
expect_log_msg("Can't set a DirPort on a bridge "
"relay; disabling DirPort\n");
@@ -2073,21 +1962,19 @@ test_options_validate__testing(void *ignored)
#define ENSURE_DEFAULT(varname, varval) \
STMT_BEGIN \
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES \
- #varname " " #varval "\n"); \
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ tdata = get_options_test_data(#varname " " #varval "\n"); \
+ ret = options_validate(NULL, tdata->opt, &msg); \
tt_str_op(msg, OP_EQ, \
#varname " may only be changed in testing Tor networks!"); \
tt_int_op(ret, OP_EQ, -1); \
tor_free(msg); \
\
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES \
- #varname " " #varval "\n" \
+ tdata = get_options_test_data(#varname " " #varval "\n" \
VALID_DIR_AUTH \
"TestingTorNetwork 1\n"); \
\
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ ret = options_validate(NULL, tdata->opt, &msg); \
if (msg) { \
tt_str_op(msg, OP_NE, \
#varname " may only be changed in testing Tor networks!"); \
@@ -2095,11 +1982,10 @@ test_options_validate__testing(void *ignored)
} \
\
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES \
- #varname " " #varval "\n" \
+ tdata = get_options_test_data(#varname " " #varval "\n" \
"___UsingTestNetworkDefaults 1\n"); \
\
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ ret = options_validate(NULL, tdata->opt, &msg);\
if (msg) { \
tt_str_op(msg, OP_NE, \
#varname " may only be changed in testing Tor networks!"); \
@@ -2112,7 +1998,6 @@ test_options_validate__testing(void *ignored)
ENSURE_DEFAULT(TestingV3AuthInitialDistDelay, 3000);
ENSURE_DEFAULT(TestingV3AuthVotingStartOffset, 3000);
ENSURE_DEFAULT(TestingAuthDirTimeToLearnReachability, 3000);
- ENSURE_DEFAULT(TestingEstimatedDescriptorPropagationTime, 3000);
ENSURE_DEFAULT(TestingServerDownloadInitialDelay, 3000);
ENSURE_DEFAULT(TestingClientDownloadInitialDelay, 3000);
ENSURE_DEFAULT(TestingServerConsensusDownloadInitialDelay, 3000);
@@ -2142,21 +2027,12 @@ test_options_validate__hidserv(void *ignored)
char *msg;
setup_capture_of_logs(LOG_WARN);
- options_test_data_t *tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES);
- tdata->opt->MinUptimeHidServDirectoryV2 = -1;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, 0);
- expect_log_msg("MinUptimeHidServDirectoryV2 "
- "option must be at least 0 seconds. Changing to 0.\n");
- tt_int_op(tdata->opt->MinUptimeHidServDirectoryV2, OP_EQ, 0);
- tor_free(msg);
+ options_test_data_t *tdata = NULL;
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RendPostPeriod 1\n" );
+ tdata = get_options_test_data("RendPostPeriod 1\n" );
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("RendPostPeriod option is too short;"
" raising to 600 seconds.\n");
@@ -2164,10 +2040,9 @@ test_options_validate__hidserv(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RendPostPeriod 302401\n" );
+ tdata = get_options_test_data("RendPostPeriod 302401\n" );
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("RendPostPeriod is too large; "
"clipping to 302400s.\n");
@@ -2189,45 +2064,40 @@ test_options_validate__path_bias(void *ignored)
char *msg;
options_test_data_t *tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"PathBiasNoticeRate 1.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"PathBiasNoticeRate is too high. It must be between 0 and 1.0");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "PathBiasWarnRate 1.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("PathBiasWarnRate 1.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"PathBiasWarnRate is too high. It must be between 0 and 1.0");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "PathBiasExtremeRate 1.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("PathBiasExtremeRate 1.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"PathBiasExtremeRate is too high. It must be between 0 and 1.0");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "PathBiasNoticeUseRate 1.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("PathBiasNoticeUseRate 1.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"PathBiasNoticeUseRate is too high. It must be between 0 and 1.0");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "PathBiasExtremeUseRate 1.1\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("PathBiasExtremeUseRate 1.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"PathBiasExtremeUseRate is too high. It must be between 0 and 1.0");
@@ -2246,130 +2116,141 @@ test_options_validate__bandwidth(void *ignored)
char *msg;
options_test_data_t *tdata = NULL;
-#define ENSURE_BANDWIDTH_PARAM(p) \
- STMT_BEGIN \
+#define ENSURE_BANDWIDTH_PARAM(p, EXTRA_OPT_STR) \
+ STMT_BEGIN \
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES #p " 3Gb\n"); \
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ tdata = get_options_test_data(EXTRA_OPT_STR \
+ #p " 3Gb\n"); \
+ ret = options_validate(NULL, tdata->opt, &msg); \
tt_int_op(ret, OP_EQ, -1); \
tt_mem_op(msg, OP_EQ, #p " (3221225471) must be at most 2147483647", 40); \
tor_free(msg); \
STMT_END
- ENSURE_BANDWIDTH_PARAM(BandwidthRate);
- ENSURE_BANDWIDTH_PARAM(BandwidthBurst);
- ENSURE_BANDWIDTH_PARAM(MaxAdvertisedBandwidth);
- ENSURE_BANDWIDTH_PARAM(RelayBandwidthRate);
- ENSURE_BANDWIDTH_PARAM(RelayBandwidthBurst);
- ENSURE_BANDWIDTH_PARAM(PerConnBWRate);
- ENSURE_BANDWIDTH_PARAM(PerConnBWBurst);
- ENSURE_BANDWIDTH_PARAM(AuthDirFastGuarantee);
- ENSURE_BANDWIDTH_PARAM(AuthDirGuardBWGuarantee);
+ ENSURE_BANDWIDTH_PARAM(BandwidthRate, "");
+ ENSURE_BANDWIDTH_PARAM(BandwidthBurst, "");
+
+ ENSURE_BANDWIDTH_PARAM(BandwidthRate, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(BandwidthBurst, ENABLE_AUTHORITY_V3);
+
+ ENSURE_BANDWIDTH_PARAM(BandwidthRate, ENABLE_AUTHORITY_BRIDGE);
+ ENSURE_BANDWIDTH_PARAM(BandwidthBurst, ENABLE_AUTHORITY_BRIDGE);
+
+ ENSURE_BANDWIDTH_PARAM(MaxAdvertisedBandwidth, "");
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthRate, "");
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthBurst, "");
+ ENSURE_BANDWIDTH_PARAM(PerConnBWRate, "");
+ ENSURE_BANDWIDTH_PARAM(PerConnBWBurst, "");
+
+ ENSURE_BANDWIDTH_PARAM(MaxAdvertisedBandwidth, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthRate, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthBurst, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(PerConnBWRate, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(PerConnBWBurst, ENABLE_AUTHORITY_V3);
+
+ ENSURE_BANDWIDTH_PARAM(MaxAdvertisedBandwidth, ENABLE_AUTHORITY_BRIDGE);
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthRate, ENABLE_AUTHORITY_BRIDGE);
+ ENSURE_BANDWIDTH_PARAM(RelayBandwidthBurst, ENABLE_AUTHORITY_BRIDGE);
+ ENSURE_BANDWIDTH_PARAM(PerConnBWRate, ENABLE_AUTHORITY_BRIDGE);
+ ENSURE_BANDWIDTH_PARAM(PerConnBWBurst, ENABLE_AUTHORITY_BRIDGE);
+
+ ENSURE_BANDWIDTH_PARAM(AuthDirFastGuarantee, ENABLE_AUTHORITY_V3);
+ ENSURE_BANDWIDTH_PARAM(AuthDirGuardBWGuarantee, ENABLE_AUTHORITY_V3);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RelayBandwidthRate 1000\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("RelayBandwidthRate 1000\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_u64_op(tdata->opt->RelayBandwidthBurst, OP_EQ, 1000);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RelayBandwidthBurst 1001\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("RelayBandwidthBurst 1001\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_u64_op(tdata->opt->RelayBandwidthRate, OP_EQ, 1001);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RelayBandwidthRate 1001\n"
+ tdata = get_options_test_data("RelayBandwidthRate 1001\n"
"RelayBandwidthBurst 1000\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "RelayBandwidthBurst must be at least equal to "
"RelayBandwidthRate.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "BandwidthRate 1001\n"
+ tdata = get_options_test_data("BandwidthRate 1001\n"
"BandwidthBurst 1000\n");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"BandwidthBurst must be at least equal to BandwidthRate.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RelayBandwidthRate 1001\n"
+ tdata = get_options_test_data("RelayBandwidthRate 1001\n"
"BandwidthRate 1000\n"
"BandwidthBurst 1000\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_u64_op(tdata->opt->BandwidthRate, OP_EQ, 1001);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "RelayBandwidthRate 1001\n"
+ tdata = get_options_test_data("RelayBandwidthRate 1001\n"
"BandwidthRate 1000\n"
"RelayBandwidthBurst 1001\n"
"BandwidthBurst 1000\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_u64_op(tdata->opt->BandwidthBurst, OP_EQ, 1001);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORPort 127.0.0.1:5555\n"
+ tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"BandwidthRate 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "BandwidthRate is set to 1 bytes/second. For servers,"
" it must be at least 76800.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORPort 127.0.0.1:5555\n"
+ tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"MaxAdvertisedBandwidth 30000\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "MaxAdvertisedBandwidth is set to 30000 bytes/second."
" For servers, it must be at least 38400.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORPort 127.0.0.1:5555\n"
+ tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"RelayBandwidthRate 1\n"
"MaxAdvertisedBandwidth 38400\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "RelayBandwidthRate is set to 1 bytes/second. For "
"servers, it must be at least 76800.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORPort 127.0.0.1:5555\n"
+ tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"BandwidthBurst 76800\n"
"RelayBandwidthRate 76800\n"
"MaxAdvertisedBandwidth 38400\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
@@ -2388,9 +2269,8 @@ test_options_validate__circuits(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "MaxCircuitDirtiness 2592001\n");
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("MaxCircuitDirtiness 2592001\n");
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("MaxCircuitDirtiness option is too "
"high; setting to 30 days.\n");
tt_int_op(tdata->opt->MaxCircuitDirtiness, OP_EQ, 2592000);
@@ -2398,9 +2278,8 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "CircuitStreamTimeout 1\n");
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("CircuitStreamTimeout 1\n");
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("CircuitStreamTimeout option is too"
" short; raising to 10 seconds.\n");
tt_int_op(tdata->opt->CircuitStreamTimeout, OP_EQ, 10);
@@ -2408,9 +2287,8 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "CircuitStreamTimeout 111\n");
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("CircuitStreamTimeout 111\n");
+ options_validate(NULL, tdata->opt, &msg);
expect_no_log_msg("CircuitStreamTimeout option is too"
" short; raising to 10 seconds.\n");
tt_int_op(tdata->opt->CircuitStreamTimeout, OP_EQ, 111);
@@ -2418,9 +2296,8 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HeartbeatPeriod 1\n");
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HeartbeatPeriod 1\n");
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("HeartbeatPeriod option is too short;"
" raising to 1800 seconds.\n");
tt_int_op(tdata->opt->HeartbeatPeriod, OP_EQ, 1800);
@@ -2428,9 +2305,8 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HeartbeatPeriod 1982\n");
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HeartbeatPeriod 1982\n");
+ options_validate(NULL, tdata->opt, &msg);
expect_no_log_msg("HeartbeatPeriod option is too short;"
" raising to 1800 seconds.\n");
tt_int_op(tdata->opt->HeartbeatPeriod, OP_EQ, 1982);
@@ -2438,10 +2314,10 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data("LearnCircuitBuildTimeout 0\n"
"CircuitBuildTimeout 1\n"
);
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_log_msg("CircuitBuildTimeout is shorter (1"
" seconds) than the recommended minimum (10 seconds), and "
"LearnCircuitBuildTimeout is disabled. If tor isn't working, "
@@ -2450,10 +2326,9 @@ test_options_validate__circuits(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "CircuitBuildTimeout 11\n"
+ tdata = get_options_test_data("CircuitBuildTimeout 11\n"
);
- options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ options_validate(NULL, tdata->opt, &msg);
expect_no_log_msg("CircuitBuildTimeout is shorter (1 "
"seconds) than the recommended minimum (10 seconds), and "
"LearnCircuitBuildTimeout is disabled. If tor isn't working, "
@@ -2477,51 +2352,46 @@ test_options_validate__rend(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(
"UseEntryGuards 0\n"
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
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);
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"UseEntryGuards 1\n"
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
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);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HiddenServicePort 80 127.0.0.1:8080\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HiddenServicePort 80 127.0.0.1:8080\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Failed to configure rendezvous options. See logs for details.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HidServAuth failed\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HidServAuth failed\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Failed to configure client authorization for hidden "
"services. See logs for details.");
@@ -2545,11 +2415,10 @@ test_options_validate__single_onion(void *ignored)
/* Test that HiddenServiceSingleHopMode must come with
* HiddenServiceNonAnonymousMode */
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 0\n"
+ tdata = get_options_test_data("SOCKSPort 0\n"
"HiddenServiceSingleHopMode 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceSingleHopMode does not provide any "
"server anonymity. It must be used with "
@@ -2557,12 +2426,11 @@ test_options_validate__single_onion(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 0\n"
+ tdata = get_options_test_data("SOCKSPort 0\n"
"HiddenServiceSingleHopMode 1\n"
"HiddenServiceNonAnonymousMode 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceSingleHopMode does not provide any "
"server anonymity. It must be used with "
@@ -2570,23 +2438,21 @@ test_options_validate__single_onion(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 0\n"
+ tdata = get_options_test_data("SOCKSPort 0\n"
"HiddenServiceSingleHopMode 1\n"
"HiddenServiceNonAnonymousMode 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
free_options_test_data(tdata);
/* Test that SOCKSPort if HiddenServiceSingleHopMode is 1 */
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 5000\n"
+ tdata = get_options_test_data("SOCKSPort 5000\n"
"HiddenServiceSingleHopMode 1\n"
"HiddenServiceNonAnonymousMode 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceNonAnonymousMode is incompatible with "
"using Tor as an anonymous client. Please set "
@@ -2595,32 +2461,30 @@ test_options_validate__single_onion(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 0\n"
+ tdata = get_options_test_data("SOCKSPort 0\n"
"HiddenServiceSingleHopMode 1\n"
"HiddenServiceNonAnonymousMode 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "SOCKSPort 5000\n"
+ tdata = get_options_test_data("SOCKSPort 5000\n"
"HiddenServiceSingleHopMode 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
free_options_test_data(tdata);
/* Test that a hidden service can't be run in non anonymous mode. */
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(
"HiddenServiceNonAnonymousMode 1\n"
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceNonAnonymousMode does not provide any "
"server anonymity. It must be used with "
@@ -2628,10 +2492,10 @@ test_options_validate__single_onion(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(
"HiddenServiceNonAnonymousMode 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceNonAnonymousMode does not provide any "
"server anonymity. It must be used with "
@@ -2639,23 +2503,23 @@ test_options_validate__single_onion(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(
"HiddenServiceNonAnonymousMode 1\n"
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
"HiddenServiceSingleHopMode 1\n"
"SOCKSPort 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_ptr_op(msg, OP_EQ, NULL);
@@ -2676,53 +2540,56 @@ test_options_validate__accounting(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccountingRule something_bad\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccountingRule something_bad\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "AccountingRule must be 'sum', 'max', 'in', or 'out'");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccountingRule sum\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccountingRule sum\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->AccountingRule, OP_EQ, ACCT_SUM);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccountingRule max\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccountingRule max\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->AccountingRule, OP_EQ, ACCT_MAX);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccountingStart fail\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccountingRule in\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(tdata->opt->AccountingRule, OP_EQ, ACCT_IN);
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data("AccountingRule out\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(tdata->opt->AccountingRule, OP_EQ, ACCT_OUT);
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data("AccountingStart fail\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Failed to parse accounting options. See logs for details.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccountingMax 10\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccountingMax 10\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"BandwidthBurst 76800\n"
@@ -2732,7 +2599,7 @@ test_options_validate__accounting(void *ignored)
"AccountingMax 10\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("Using accounting with a hidden "
"service and an ORPort is risky: your hidden service(s) and "
@@ -2743,13 +2610,12 @@ test_options_validate__accounting(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
"AccountingMax 10\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg("Using accounting with a hidden "
"service and an ORPort is risky: your hidden service(s) and "
@@ -2760,7 +2626,6 @@ test_options_validate__accounting(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service2/\n"
@@ -2768,7 +2633,7 @@ test_options_validate__accounting(void *ignored)
"AccountingMax 10\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("Using accounting with multiple "
"hidden services is risky: they will all turn off at the same"
@@ -2795,36 +2660,29 @@ test_options_validate__proxy(void *ignored)
MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 127.0.42.1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpProxy 127.0.42.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->HTTPProxyPort, OP_EQ, 80);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 127.0.42.1:444\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpProxy 127.0.42.1:444\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->HTTPProxyPort, OP_EQ, 444);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy not_so_valid!\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpProxy not_so_valid!\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HTTPProxy failed to parse or resolve. Please fix.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxyAuthenticator "
+ tdata = get_options_test_data("HttpProxyAuthenticator "
"onetwothreonetwothreonetwothreonetwothreonetw"
"othreonetwothreonetwothreonetwothreonetwothre"
"onetwothreonetwothreonetwothreonetwothreonetw"
@@ -2837,52 +2695,41 @@ test_options_validate__proxy(void *ignored)
"othreonetwothreonetwothreonetwothreonetwothre"
"onetwothreonetwothreonetwothreonetwothreonetw"
"othreonetwothreeonetwothreeonetwothree"
-
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HTTPProxyAuthenticator is too long (>= 512 chars).");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxyAuthenticator validauth\n"
-
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpProxyAuthenticator validauth\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpsProxy 127.0.42.1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpsProxy 127.0.42.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->HTTPSProxyPort, OP_EQ, 443);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpsProxy 127.0.42.1:444\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpsProxy 127.0.42.1:444\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->HTTPSProxyPort, OP_EQ, 444);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpsProxy not_so_valid!\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpsProxy not_so_valid!\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HTTPSProxy failed to parse or resolve. Please fix.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpsProxyAuthenticator "
+ tdata = get_options_test_data("HttpsProxyAuthenticator "
"onetwothreonetwothreonetwothreonetwothreonetw"
"othreonetwothreonetwothreonetwothreonetwothre"
"onetwothreonetwothreonetwothreonetwothreonetw"
@@ -2897,103 +2744,86 @@ test_options_validate__proxy(void *ignored)
"othreonetwothreeonetwothreeonetwothree"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HTTPSProxyAuthenticator is too long (>= 512 chars).");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpsProxyAuthenticator validauth\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("HttpsProxyAuthenticator validauth\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks4Proxy 127.0.42.1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks4Proxy 127.0.42.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->Socks4ProxyPort, OP_EQ, 1080);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks4Proxy 127.0.42.1:444\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks4Proxy 127.0.42.1:444\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->Socks4ProxyPort, OP_EQ, 444);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks4Proxy not_so_valid!\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks4Proxy not_so_valid!\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Socks4Proxy failed to parse or resolve. Please fix.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5Proxy 127.0.42.1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5Proxy 127.0.42.1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->Socks5ProxyPort, OP_EQ, 1080);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5Proxy 127.0.42.1:444\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5Proxy 127.0.42.1:444\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(tdata->opt->Socks5ProxyPort, OP_EQ, 444);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5Proxy not_so_valid!\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5Proxy not_so_valid!\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Socks5Proxy failed to parse or resolve. Please fix.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks4Proxy 215.1.1.1\n"
+ tdata = get_options_test_data("Socks4Proxy 215.1.1.1\n"
"Socks5Proxy 215.1.1.2\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "You have configured more than one proxy type. "
- "(Socks4Proxy|Socks5Proxy|HTTPSProxy)");
+ "(Socks4Proxy|Socks5Proxy|HTTPSProxy|TCPProxy)");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 215.1.1.1\n"
- );
+ tdata = get_options_test_data("HttpProxy 215.1.1.1\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg("HTTPProxy configured, but no SOCKS "
- "proxy or HTTPS proxy configured. Watch out: this configuration "
- "will proxy unencrypted directory connections only.\n");
+ expect_log_msg("HTTPProxy configured, but no SOCKS proxy, "
+ "HTTPS proxy, or any other TCP proxy configured. Watch out: "
+ "this configuration will proxy unencrypted directory "
+ "connections only.\n");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 215.1.1.1\n"
+ tdata = get_options_test_data("HttpProxy 215.1.1.1\n"
"Socks4Proxy 215.1.1.1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg("HTTPProxy configured, but no SOCKS "
"proxy or HTTPS proxy configured. Watch out: this configuration "
@@ -3001,12 +2831,11 @@ test_options_validate__proxy(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 215.1.1.1\n"
+ tdata = get_options_test_data("HttpProxy 215.1.1.1\n"
"Socks5Proxy 215.1.1.1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg("HTTPProxy configured, but no SOCKS "
"proxy or HTTPS proxy configured. Watch out: this configuration "
@@ -3014,12 +2843,11 @@ test_options_validate__proxy(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HttpProxy 215.1.1.1\n"
+ tdata = get_options_test_data("HttpProxy 215.1.1.1\n"
"HttpsProxy 215.1.1.1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"HTTPProxy configured, but no SOCKS proxy or HTTPS proxy "
@@ -3028,81 +2856,69 @@ test_options_validate__proxy(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- );
+ tdata = get_options_test_data("");
tdata->opt->Socks5ProxyUsername = tor_strdup("");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Socks5ProxyUsername must be between 1 and 255 characters.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- );
+ tdata = get_options_test_data("");
tdata->opt->Socks5ProxyUsername =
tor_strdup("ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789AB"
"CDEABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCD"
"EABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEA"
"BCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEABC"
"DE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Socks5ProxyUsername must be between 1 and 255 characters.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5ProxyUsername hello_world\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5ProxyUsername hello_world\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Socks5ProxyPassword must be included with "
"Socks5ProxyUsername.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5ProxyUsername hello_world\n"
- );
+ tdata = get_options_test_data("Socks5ProxyUsername hello_world\n");
tdata->opt->Socks5ProxyPassword = tor_strdup("");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Socks5ProxyPassword must be between 1 and 255 characters.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5ProxyUsername hello_world\n"
- );
+ tdata = get_options_test_data("Socks5ProxyUsername hello_world\n");
tdata->opt->Socks5ProxyPassword =
tor_strdup("ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789AB"
"CDEABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCD"
"EABCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEA"
"BCDE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789ABCDEABC"
"DE0123456789ABCDEABCDE0123456789ABCDEABCDE0123456789");
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Socks5ProxyPassword must be between 1 and 255 characters.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5ProxyUsername hello_world\n"
- "Socks5ProxyPassword world_hello\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5ProxyUsername hello_world\n"
+ "Socks5ProxyPassword world_hello\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "Socks5ProxyPassword hello_world\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("Socks5ProxyPassword hello_world\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Socks5ProxyPassword must be included with "
"Socks5ProxyUsername.");
@@ -3127,69 +2943,62 @@ test_options_validate__control(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HashedControlPassword something_incorrect\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data(
+ "HashedControlPassword something_incorrect\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Bad HashedControlPassword: wrong length or bad encoding");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "HashedControlPassword 16:872860B76453A77D60CA"
+ tdata = get_options_test_data("HashedControlPassword 16:872860B76453A77D60CA"
"2BB8C1A7042072093276A3D701AD684053EC4C\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"__HashedControlSessionPassword something_incorrect\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Bad HashedControlSessionPassword: wrong length or "
"bad encoding");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "__HashedControlSessionPassword 16:872860B7645"
+ tdata = get_options_test_data("__HashedControlSessionPassword 16:872860B7645"
"3A77D60CA2BB8C1A7042072093276A3D701AD684053EC"
"4C\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data(
- TEST_OPTIONS_DEFAULT_VALUES
"__OwningControllerProcess something_incorrect\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Bad OwningControllerProcess: invalid PID");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "__OwningControllerProcess 123\n"
+ tdata = get_options_test_data("__OwningControllerProcess 123\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlPort 127.0.0.1:1234\n"
+ tdata = get_options_test_data("ControlPort 127.0.0.1:1234\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"ControlPort is open, but no authentication method has been "
@@ -3199,13 +3008,12 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlPort 127.0.0.1:1234\n"
+ tdata = get_options_test_data("ControlPort 127.0.0.1:1234\n"
"HashedControlPassword 16:872860B76453A77D60CA"
"2BB8C1A7042072093276A3D701AD684053EC4C\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlPort is open, but no authentication method has been "
@@ -3215,14 +3023,13 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlPort 127.0.0.1:1234\n"
+ tdata = get_options_test_data("ControlPort 127.0.0.1:1234\n"
"__HashedControlSessionPassword 16:872860B7645"
"3A77D60CA2BB8C1A7042072093276A3D701AD684053EC"
"4C\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlPort is open, but no authentication method has been "
@@ -3232,12 +3039,11 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlPort 127.0.0.1:1234\n"
+ tdata = get_options_test_data("ControlPort 127.0.0.1:1234\n"
"CookieAuthentication 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlPort is open, but no authentication method has been "
@@ -3248,11 +3054,9 @@ test_options_validate__control(void *ignored)
#ifdef HAVE_SYS_UN_H
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlSocket unix:/tmp WorldWritable\n"
- );
+ tdata = get_options_test_data("ControlSocket unix:/tmp WorldWritable\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"ControlSocket is world writable, but no authentication method has"
@@ -3262,13 +3066,12 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlSocket unix:/tmp WorldWritable\n"
+ tdata = get_options_test_data("ControlSocket unix:/tmp WorldWritable\n"
"HashedControlPassword 16:872860B76453A77D60CA"
"2BB8C1A7042072093276A3D701AD684053EC4C\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlSocket is world writable, but no authentication method has"
@@ -3278,14 +3081,13 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlSocket unix:/tmp WorldWritable\n"
+ tdata = get_options_test_data("ControlSocket unix:/tmp WorldWritable\n"
"__HashedControlSessionPassword 16:872860B7645"
"3A77D60CA2BB8C1A7042072093276A3D701AD684053EC"
"4C\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlSocket is world writable, but no authentication method has"
@@ -3295,12 +3097,11 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ControlSocket unix:/tmp WorldWritable\n"
+ tdata = get_options_test_data("ControlSocket unix:/tmp WorldWritable\n"
"CookieAuthentication 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"ControlSocket is world writable, but no authentication method has"
@@ -3311,11 +3112,10 @@ test_options_validate__control(void *ignored)
#endif /* defined(HAVE_SYS_UN_H) */
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "CookieAuthFileGroupReadable 1\n"
+ tdata = get_options_test_data("CookieAuthFileGroupReadable 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"CookieAuthFileGroupReadable is set, but will have no effect: you "
@@ -3324,12 +3124,11 @@ test_options_validate__control(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "CookieAuthFileGroupReadable 1\n"
+ tdata = get_options_test_data("CookieAuthFileGroupReadable 1\n"
"CookieAuthFile /tmp/somewhere\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"CookieAuthFileGroupReadable is set, but will have no effect: you "
@@ -3354,8 +3153,7 @@ test_options_validate__families(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "MyFamily home\n"
+ tdata = get_options_test_data("MyFamily home\n"
"BridgeRelay 1\n"
"ORPort 127.0.0.1:5555\n"
"BandwidthRate 51300\n"
@@ -3364,7 +3162,7 @@ test_options_validate__families(void *ignored)
"DirCache 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"Listing a family for a bridge relay is not supported: it can "
@@ -3374,11 +3172,9 @@ test_options_validate__families(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "MyFamily home\n"
- );
+ tdata = get_options_test_data("MyFamily home\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"Listing a family for a bridge relay is not supported: it can "
@@ -3388,22 +3184,18 @@ test_options_validate__families(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "MyFamily !\n"
- );
+ tdata = get_options_test_data("MyFamily !\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Invalid nickname '!' in MyFamily line");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "NodeFamily foo\n"
- "NodeFamily !\n"
- );
+ tdata = get_options_test_data("NodeFamily foo\n"
+ "NodeFamily !\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_assert(!msg);
tor_free(msg);
@@ -3424,11 +3216,10 @@ test_options_validate__addr_policies(void *ignored)
options_test_data_t *tdata = NULL;
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ExitPolicy !!!\n"
+ tdata = get_options_test_data("ExitPolicy !!!\n"
"ExitRelay 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Error in ExitPolicy entry.");
tor_free(msg);
@@ -3449,12 +3240,11 @@ test_options_validate__dir_auth(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- VALID_DIR_AUTH
+ tdata = get_options_test_data(VALID_DIR_AUTH
VALID_ALT_DIR_AUTH
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Directory authority/fallback line did not parse. See logs for "
@@ -3464,10 +3254,8 @@ test_options_validate__dir_auth(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingTorNetwork 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("TestingTorNetwork 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"TestingTorNetwork may only be configured in combination with a "
@@ -3476,20 +3264,18 @@ test_options_validate__dir_auth(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- VALID_DIR_AUTH
+ tdata = get_options_test_data(VALID_DIR_AUTH
"TestingTorNetwork 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingTorNetwork 1\n"
+ tdata = get_options_test_data("TestingTorNetwork 1\n"
VALID_ALT_DIR_AUTH
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"TestingTorNetwork may only be configured in combination with a "
@@ -3498,11 +3284,10 @@ test_options_validate__dir_auth(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingTorNetwork 1\n"
+ tdata = get_options_test_data("TestingTorNetwork 1\n"
VALID_ALT_BRIDGE_AUTH
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingTorNetwork may only be configured in "
"combination with a non-default set of DirAuthority or both of "
@@ -3510,12 +3295,11 @@ test_options_validate__dir_auth(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- VALID_ALT_DIR_AUTH
+ tdata = get_options_test_data(VALID_ALT_DIR_AUTH
VALID_ALT_BRIDGE_AUTH
"TestingTorNetwork 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
@@ -3536,11 +3320,10 @@ test_options_validate__transport(void *ignored)
setup_capture_of_logs(LOG_NOTICE);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientTransportPlugin !!\n"
+ tdata = get_options_test_data("ClientTransportPlugin !!\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Invalid client transport line. See logs for details.");
@@ -3549,20 +3332,17 @@ test_options_validate__transport(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ClientTransportPlugin foo exec bar\n"
+ tdata = get_options_test_data("ClientTransportPlugin foo exec bar\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportPlugin !!\n"
- );
+ tdata = get_options_test_data("ServerTransportPlugin !!\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Invalid server transport line. See logs for details.");
@@ -3571,11 +3351,9 @@ test_options_validate__transport(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportPlugin foo exec bar\n"
- );
+ tdata = get_options_test_data("ServerTransportPlugin foo exec bar\n");
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"Tor is not configured as a relay but you specified a "
@@ -3584,15 +3362,14 @@ test_options_validate__transport(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportPlugin foo exec bar\n"
+ tdata = get_options_test_data("ServerTransportPlugin foo exec bar\n"
"ORPort 127.0.0.1:5555\n"
"BandwidthRate 76900\n"
"BandwidthBurst 76900\n"
"MaxAdvertisedBandwidth 38500\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"Tor is not configured as a relay but you specified a "
@@ -3601,22 +3378,19 @@ test_options_validate__transport(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportListenAddr foo 127.0.0.42:55\n"
- "ServerTransportListenAddr !\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("ServerTransportListenAddr foo 127.0.0.42:55\n"
+ "ServerTransportListenAddr !\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"ServerTransportListenAddr did not parse. See logs for details.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportListenAddr foo 127.0.0.42:55\n"
+ tdata = get_options_test_data("ServerTransportListenAddr foo 127.0.0.42:55\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg(
"You need at least a single managed-proxy to specify a transport "
@@ -3625,8 +3399,7 @@ test_options_validate__transport(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ServerTransportListenAddr foo 127.0.0.42:55\n"
+ tdata = get_options_test_data("ServerTransportListenAddr foo 127.0.0.42:55\n"
"ServerTransportPlugin foo exec bar\n"
"ORPort 127.0.0.1:5555\n"
"BandwidthRate 76900\n"
@@ -3634,7 +3407,7 @@ test_options_validate__transport(void *ignored)
"MaxAdvertisedBandwidth 38500\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"You need at least a single managed-proxy to specify a transport "
@@ -3659,50 +3432,46 @@ test_options_validate__constrained_sockets(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ConstrainedSockets 1\n"
+ tdata = get_options_test_data("ConstrainedSockets 1\n"
"ConstrainedSockSize 0\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "ConstrainedSockSize is invalid. Must be a value "
"between 2048 and 262144 in 1024 byte increments.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ConstrainedSockets 1\n"
+ tdata = get_options_test_data("ConstrainedSockets 1\n"
"ConstrainedSockSize 263168\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "ConstrainedSockSize is invalid. Must be a value "
"between 2048 and 262144 in 1024 byte increments.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ConstrainedSockets 1\n"
+ tdata = get_options_test_data("ConstrainedSockets 1\n"
"ConstrainedSockSize 2047\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "ConstrainedSockSize is invalid. Must be a value "
"between 2048 and 262144 in 1024 byte increments.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ConstrainedSockets 1\n"
+ tdata = get_options_test_data("ConstrainedSockets 1\n"
"ConstrainedSockSize 2048\n"
"DirPort 999\n"
"DirCache 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("You have requested constrained "
"socket buffers while also serving directory entries via DirPort."
@@ -3711,12 +3480,11 @@ test_options_validate__constrained_sockets(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ConstrainedSockets 1\n"
+ tdata = get_options_test_data("ConstrainedSockets 1\n"
"ConstrainedSockSize 2048\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg(
"You have requested constrained socket buffers while also serving"
@@ -3742,12 +3510,12 @@ test_options_validate__v3_auth(void *ignored)
setup_capture_of_logs(LOG_WARN);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 1000\n"
"V3AuthDistDelay 1000\n"
"V3AuthVotingInterval 1000\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
@@ -3755,20 +3523,18 @@ test_options_validate__v3_auth(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "V3AuthVoteDelay 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "V3AuthVoteDelay 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthVoteDelay is way too low.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 1\n"
- "TestingTorNetwork 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ "TestingTorNetwork 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthVoteDelay is way too low.");
tor_free(msg);
@@ -3778,87 +3544,127 @@ test_options_validate__v3_auth(void *ignored)
// since they are the same
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "V3AuthDistDelay 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "V3AuthDistDelay 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthDistDelay is way too low.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthDistDelay 1\n"
"TestingTorNetwork 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthDistDelay is way too low.");
tor_free(msg);
- // TODO: we can't reach the case of v3authdistdelay lower than
+ // We can't reach the case of v3authdistdelay lower than
// MIN_DIST_SECONDS but not lower than MIN_DIST_SECONDS_TESTING,
// since they are the same
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthNIntervalsValid 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthNIntervalsValid must be at least 2.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 49\n"
"V3AuthDistDelay 49\n"
"V3AuthVotingInterval 200\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthVotingInterval is insanely low.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "V3AuthVoteDelay 49\n"
+ "V3AuthDistDelay 49\n"
+ "V3AuthVotingInterval 200\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "V3AuthVoteDelay 2\n"
+ "V3AuthDistDelay 2\n"
+ "V3AuthVotingInterval 9\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ,
+ "V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
+ "V3AuthVotingInterval");
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "V3AuthVoteDelay 2\n"
+ "V3AuthDistDelay 2\n"
+ "V3AuthVotingInterval 10\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 49\n"
"V3AuthDistDelay 49\n"
"V3AuthVotingInterval 200000\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "V3AuthVotingInterval is insanely high.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 49\n"
"V3AuthDistDelay 49\n"
"V3AuthVotingInterval 1441\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("V3AuthVotingInterval does not divide"
" evenly into 24 hours.\n");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 49\n"
"V3AuthDistDelay 49\n"
"V3AuthVotingInterval 1440\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_no_log_msg("V3AuthVotingInterval does not divide"
" evenly into 24 hours.\n");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"V3AuthVoteDelay 49\n"
"V3AuthDistDelay 49\n"
"V3AuthVotingInterval 299\n"
@@ -3866,84 +3672,125 @@ test_options_validate__v3_auth(void *ignored)
"TestingTorNetwork 1\n"
);
mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg("V3AuthVotingInterval is very low. "
"This may lead to failure to synchronise for a consensus.\n");
tor_free(msg);
- // TODO: It is impossible to reach the case of testingtor network, with
- // v3authvotinginterval too low
- /* free_options_test_data(tdata); */
- /* tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES */
- /* "V3AuthVoteDelay 1\n" */
- /* "V3AuthDistDelay 1\n" */
- /* "V3AuthVotingInterval 9\n" */
- /* VALID_DIR_AUTH */
- /* "TestingTorNetwork 1\n" */
- /* ); */
- /* ret = options_validate(tdata->old_opt, tdata->opt, */
- /* tdata->def_opt, 0, &msg); */
- /* tt_int_op(ret, OP_EQ, -1); */
- /* tt_str_op(msg, OP_EQ, "V3AuthVotingInterval is insanely low."); */
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ "V3AuthVoteDelay 1\n"
+ "V3AuthDistDelay 1\n"
+ "V3AuthVotingInterval 9\n"
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ );
+ /* We have to call the dirauth-specific function to reach this case */
+ ret = options_validate_dirauth_schedule(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ, "V3AuthVoteDelay is way too low.");
+ tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"TestingV3AuthInitialVoteDelay 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingV3AuthInitialVoteDelay is way too low.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
"TestingV3AuthInitialDistDelay 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingV3AuthInitialDistDelay is way too low.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
);
tdata->opt->TestingV3AuthVotingStartOffset = 100000;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingV3AuthVotingStartOffset is higher than the "
"voting interval.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
);
tdata->opt->TestingV3AuthVotingStartOffset = -1;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"TestingV3AuthVotingStartOffset must be non-negative.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
"TestingV3AuthInitialVotingInterval 4\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingV3AuthInitialVotingInterval is insanely low.");
tor_free(msg);
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "TestingV3AuthInitialVoteDelay 2\n"
+ "TestingV3AuthInitialDistDelay 2\n"
+ "TestingV3AuthInitialVotingInterval 5\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "TestingV3AuthInitialVotingInterval 7\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ,
+ "TestingV3AuthInitialVotingInterval does not divide evenly into "
+ "30 minutes.");
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(ENABLE_AUTHORITY_V3
+ VALID_DIR_AUTH
+ "TestingTorNetwork 1\n"
+ "TestingV3AuthInitialVoteDelay 3\n"
+ "TestingV3AuthInitialDistDelay 3\n"
+ "TestingV3AuthInitialVotingInterval 5\n"
+ );
+ ret = options_validate(NULL, tdata->opt, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ,
+ "TestingV3AuthInitialVoteDelay plus "
+ "TestingV3AuthInitialDistDelay must be less than "
+ "TestingV3AuthInitialVotingInterval");
+ tor_free(msg);
+
done:
policies_free_all();
teardown_capture_of_logs();
@@ -3960,19 +3807,16 @@ test_options_validate__virtual_addr(void *ignored)
options_test_data_t *tdata = NULL;
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "VirtualAddrNetworkIPv4 !!"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("VirtualAddrNetworkIPv4 !!");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Error parsing VirtualAddressNetwork !!");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "VirtualAddrNetworkIPv6 !!"
+ tdata = get_options_test_data("VirtualAddrNetworkIPv6 !!"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Error parsing VirtualAddressNetworkIPv6 !!");
tor_free(msg);
@@ -3993,135 +3837,133 @@ test_options_validate__testing_options(void *ignored)
options_test_data_t *tdata = NULL;
setup_capture_of_logs(LOG_WARN);
-#define TEST_TESTING_OPTION(name, low_val, high_val, err_low) \
+#define TEST_TESTING_OPTION(name, accessor, \
+ low_val, high_val, err_low, EXTRA_OPT_STR) \
STMT_BEGIN \
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES \
+ tdata = get_options_test_data(EXTRA_OPT_STR \
VALID_DIR_AUTH \
"TestingTorNetwork 1\n" \
); \
- tdata->opt-> name = low_val; \
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ accessor(tdata->opt)->name = low_val; \
+ ret = options_validate(NULL, tdata->opt, &msg); \
tt_int_op(ret, OP_EQ, -1); \
tt_str_op(msg, OP_EQ, #name " " err_low); \
tor_free(msg); \
\
free_options_test_data(tdata); \
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES \
+ tdata = get_options_test_data(EXTRA_OPT_STR \
VALID_DIR_AUTH \
"TestingTorNetwork 1\n" \
); \
- tdata->opt-> name = high_val; \
+ accessor(tdata->opt)->name = high_val; \
mock_clean_saved_logs(); \
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);\
+ ret = options_validate(NULL, tdata->opt, &msg); \
tt_int_op(ret, OP_EQ, 0); \
+ tt_ptr_op(msg, OP_EQ, NULL); \
expect_log_msg( #name " is insanely high.\n"); \
tor_free(msg); \
STMT_END
- TEST_TESTING_OPTION(TestingAuthDirTimeToLearnReachability, -1, 8000,
- "must be non-negative.");
- TEST_TESTING_OPTION(TestingEstimatedDescriptorPropagationTime, -1, 3601,
- "must be non-negative.");
- TEST_TESTING_OPTION(TestingClientMaxIntervalWithoutRequest, -1, 3601,
- "is way too low.");
- TEST_TESTING_OPTION(TestingDirConnectionMaxStall, 1, 3601,
- "is way too low.");
+ TEST_TESTING_OPTION(TestingClientMaxIntervalWithoutRequest, , -1, 3601,
+ "is way too low.", "");
+ TEST_TESTING_OPTION(TestingDirConnectionMaxStall, , 1, 3601,
+ "is way too low.", "");
+
+ TEST_TESTING_OPTION(TestingClientMaxIntervalWithoutRequest, , -1, 3601,
+ "is way too low.", ENABLE_AUTHORITY_V3);
+ TEST_TESTING_OPTION(TestingDirConnectionMaxStall, , 1, 3601,
+ "is way too low.", ENABLE_AUTHORITY_V3);
+
+ TEST_TESTING_OPTION(TestingClientMaxIntervalWithoutRequest, , -1, 3601,
+ "is way too low.", ENABLE_AUTHORITY_BRIDGE);
+ TEST_TESTING_OPTION(TestingDirConnectionMaxStall, , 1, 3601,
+ "is way too low.", ENABLE_AUTHORITY_BRIDGE);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableConnBwEvent 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("TestingEnableConnBwEvent 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingEnableConnBwEvent may only be changed in "
"testing Tor networks!");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableConnBwEvent 1\n"
+ tdata = get_options_test_data("TestingEnableConnBwEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
"___UsingTestNetworkDefaults 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableConnBwEvent 1\n"
+ tdata = get_options_test_data("TestingEnableConnBwEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 0\n"
"___UsingTestNetworkDefaults 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableCellStatsEvent 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("TestingEnableCellStatsEvent 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "TestingEnableCellStatsEvent may only be changed in "
"testing Tor networks!");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableCellStatsEvent 1\n"
+ tdata = get_options_test_data("TestingEnableCellStatsEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
"___UsingTestNetworkDefaults 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableCellStatsEvent 1\n"
+ tdata = get_options_test_data("TestingEnableCellStatsEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 0\n"
"___UsingTestNetworkDefaults 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableTbEmptyEvent 1\n"
+ tdata = get_options_test_data("TestingEnableTbEmptyEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 1\n"
"___UsingTestNetworkDefaults 0\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "TestingEnableTbEmptyEvent 1\n"
+ tdata = get_options_test_data("TestingEnableTbEmptyEvent 1\n"
VALID_DIR_AUTH
"TestingTorNetwork 0\n"
"___UsingTestNetworkDefaults 1\n"
);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tt_assert(!msg);
tor_free(msg);
@@ -4142,40 +3984,32 @@ test_options_validate__accel(void *ignored)
options_test_data_t *tdata = NULL;
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccelName foo\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccelName foo\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
- tt_int_op(tdata->opt->HardwareAccel, OP_EQ, 1);
+ tt_int_op(get_crypto_options(tdata->opt)->HardwareAccel, OP_EQ, 0);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccelName foo\n"
- );
- tdata->opt->HardwareAccel = 2;
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccelName foo\n");
+ get_crypto_options(tdata->opt)->HardwareAccel = 2;
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
- tt_int_op(tdata->opt->HardwareAccel, OP_EQ, 2);
+ tt_int_op(get_crypto_options(tdata->opt)->HardwareAccel, OP_EQ, 2);
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccelDir 1\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccelDir 1\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ,
"Can't use hardware crypto accelerator dir without engine name.");
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AccelDir 1\n"
- "AccelName something\n"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tdata = get_options_test_data("AccelDir 1\n"
+ "AccelName something\n");
+ ret = options_validate(NULL, tdata->opt, &msg);
tt_int_op(ret, OP_EQ, 0);
tor_free(msg);
@@ -4185,8 +4019,280 @@ test_options_validate__accel(void *ignored)
tor_free(msg);
}
+static int mocked_granularity;
+
+static void
+mock_set_log_time_granularity(int g)
+{
+ mocked_granularity = g;
+}
+
+static void
+test_options_init_logs_granularity(void *arg)
+{
+ options_test_data_t *tdata = get_options_test_data("");
+ int rv;
+ (void) arg;
+
+ MOCK(set_log_time_granularity, mock_set_log_time_granularity);
+
+ /* Reasonable value. */
+ tdata->opt->LogTimeGranularity = 100;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 100);
+
+ /* Doesn't divide 1000. */
+ tdata->opt->LogTimeGranularity = 249;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 250);
+
+ /* Doesn't divide 1000. */
+ tdata->opt->LogTimeGranularity = 3;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 4);
+
+ /* Not a multiple of 1000. */
+ tdata->opt->LogTimeGranularity = 1500;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 2000);
+
+ /* Reasonable value. */
+ tdata->opt->LogTimeGranularity = 3000;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 3000);
+
+ /* Negative. (Shouldn't be allowed by rest of config parsing.) */
+ tdata->opt->LogTimeGranularity = -1;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, -1);
+
+ /* Very big */
+ tdata->opt->LogTimeGranularity = 3600 * 1000;
+ mocked_granularity = -1;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(mocked_granularity, OP_EQ, 3600 * 1000);
+
+ done:
+ free_options_test_data(tdata);
+ UNMOCK(set_log_time_granularity);
+}
+
+typedef struct {
+ char *name;
+ log_severity_list_t sev;
+ int fd;
+ bool stream;
+} added_log_t;
+
+static smartlist_t *added_logs = NULL;
+
+static void
+mock_add_stream_log_impl(const log_severity_list_t *sev, const char *name,
+ int fd)
+{
+ added_log_t *a = tor_malloc_zero(sizeof(added_log_t));
+ a->name = tor_strdup(name);
+ memcpy(&a->sev, sev, sizeof(log_severity_list_t));
+ a->fd = fd;
+ a->stream = true;
+ smartlist_add(added_logs, a);
+}
+
+static int
+mock_add_file_log(const log_severity_list_t *sev, const char *name, int fd)
+{
+ added_log_t *a = tor_malloc_zero(sizeof(added_log_t));
+ a->name = tor_strdup(name);
+ memcpy(&a->sev, sev, sizeof(log_severity_list_t));
+ a->fd = fd;
+ smartlist_add(added_logs, a);
+ return 0;
+}
+
+static void
+clear_added_logs(void)
+{
+ SMARTLIST_FOREACH(added_logs, added_log_t *, a,
+ { tor_free(a->name); tor_free(a); });
+ smartlist_clear(added_logs);
+}
+
+static void
+test_options_init_logs_quiet(void *arg)
+{
+ (void)arg;
+ char *cfg = NULL;
+ options_test_data_t *tdata = get_options_test_data("");
+ char *fn1 = tor_strdup(get_fname_rnd("log"));
+ const added_log_t *a;
+ int rv;
+ tdata->opt->RunAsDaemon = 0;
+
+ added_logs = smartlist_new();
+ MOCK(add_stream_log_impl, mock_add_stream_log_impl);
+ MOCK(add_file_log, mock_add_file_log);
+
+ tt_ptr_op(tdata->opt->Logs, OP_EQ, NULL);
+
+ /* First, try with no configured logs, and make sure that our configured
+ logs match the quiet level. */
+ quiet_level = QUIET_SILENT;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(smartlist_len(added_logs), OP_EQ, 0);
+
+ quiet_level = QUIET_HUSH;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(smartlist_len(added_logs), OP_EQ, 1);
+ a = smartlist_get(added_logs, 0);
+ tt_assert(a);
+ tt_assert(a->stream);
+ tt_int_op(a->fd, OP_EQ, fileno(stdout));
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_INFO)], OP_EQ, 0);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_NOTICE)], OP_EQ, 0);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_WARN)], OP_EQ, LD_ALL_DOMAINS);
+ clear_added_logs();
+
+ quiet_level = QUIET_NONE;
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(smartlist_len(added_logs), OP_EQ, 1);
+ a = smartlist_get(added_logs, 0);
+ tt_assert(a);
+ tt_assert(a->stream);
+ tt_int_op(a->fd, OP_EQ, fileno(stdout));
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_INFO)], OP_EQ, 0);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_NOTICE)], OP_EQ,
+ LD_ALL_DOMAINS);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_WARN)], OP_EQ, LD_ALL_DOMAINS);
+ clear_added_logs();
+
+ /* Make sure that adding a configured log makes the default logs go away. */
+ tor_asprintf(&cfg, "Log info file %s\n", fn1);
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(cfg);
+ rv = options_init_logs(NULL, tdata->opt, 0);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_int_op(smartlist_len(added_logs), OP_EQ, 1);
+ a = smartlist_get(added_logs, 0);
+ tt_assert(a);
+ tt_assert(! a->stream);
+ tt_int_op(a->fd, OP_NE, fileno(stdout));
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_INFO)], OP_EQ, LD_ALL_DOMAINS);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_NOTICE)], OP_EQ,
+ LD_ALL_DOMAINS);
+ tt_u64_op(a->sev.masks[SEVERITY_MASK_IDX(LOG_WARN)], OP_EQ, LD_ALL_DOMAINS);
+
+ done:
+ free_options_test_data(tdata);
+ tor_free(fn1);
+ tor_free(cfg);
+ clear_added_logs();
+ smartlist_free(added_logs);
+ UNMOCK(add_stream_log_impl);
+ UNMOCK(add_file_log);
+}
+
+static int mock_options_act_status = 0;
+static int
+mock_options_act(const or_options_t *old_options)
+{
+ (void)old_options;
+ return mock_options_act_status;
+}
+static int
+mock_options_act_reversible(const or_options_t *old_options, char **msg_out)
+{
+ (void)old_options;
+ (void)msg_out;
+ return 0;
+}
+
+static void
+test_options_trial_assign(void *arg)
+{
+ (void)arg;
+ setopt_err_t v;
+ config_line_t *lines = NULL;
+ char *msg = NULL;
+ int r;
+
+ // replace options_act*() so that we don't actually launch tor here.
+ MOCK(options_act, mock_options_act);
+ MOCK(options_act_reversible, mock_options_act_reversible);
+
+ // Try assigning nothing; that should work.
+ v = options_trial_assign(lines, 0, &msg);
+ if (msg)
+ puts(msg);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(v, OP_EQ, SETOPT_OK);
+
+ // Assigning a nickname is okay
+ r = config_get_lines("Nickname Hemiramphinae", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ v = options_trial_assign(lines, 0, &msg);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(v, OP_EQ, SETOPT_OK);
+ tt_str_op(get_options()->Nickname, OP_EQ, "Hemiramphinae");
+ config_free_lines(lines);
+
+ // We can't change the User; that's a transition error.
+ r = config_get_lines("User Heraclitus", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ v = options_trial_assign(lines, 0, &msg);
+ tt_int_op(v, OP_EQ, SETOPT_ERR_TRANSITION);
+ tt_str_op(msg, OP_EQ, "While Tor is running, changing User is not allowed");
+ tor_free(msg);
+ config_free_lines(lines);
+
+ // We can't set the ORPort to nonsense: that's a validation error.
+ r = config_get_lines("ORPort fractabling planished", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ v = options_trial_assign(lines, 0, &msg);
+ tt_int_op(v, OP_EQ, SETOPT_ERR_PARSE); // (same error code for now)
+ tt_str_op(msg, OP_EQ, "Invalid ORPort configuration");
+ tor_free(msg);
+ config_free_lines(lines);
+
+ // We can't set UseBridges to a non-boolean: that's a parse error.
+ r = config_get_lines("UseBridges ambidextrous", &lines, 0);
+ tt_int_op(r, OP_EQ, 0);
+ v = options_trial_assign(lines, 0, &msg);
+ tt_int_op(v, OP_EQ, SETOPT_ERR_PARSE);
+ tt_str_op(msg, OP_EQ,
+ "Could not parse UseBridges: Unrecognized value ambidextrous. "
+ "Allowed values are 0 and 1.");
+ tor_free(msg);
+ config_free_lines(lines);
+
+ // this didn't change.
+ tt_str_op(get_options()->Nickname, OP_EQ, "Hemiramphinae");
+
+ done:
+ config_free_lines(lines);
+ tor_free(msg);
+ UNMOCK(options_act);
+ UNMOCK(options_act_reversible);
+}
+
+#ifndef COCCI
#define LOCAL_VALIDATE_TEST(name) \
{ "validate__" #name, test_options_validate__ ## name, TT_FORK, NULL, NULL }
+#endif
struct testcase_t options_tests[] = {
{ "validate", test_options_validate, TT_FORK, NULL, NULL },
@@ -4199,11 +4305,11 @@ struct testcase_t options_tests[] = {
LOCAL_VALIDATE_TEST(logs),
LOCAL_VALIDATE_TEST(authdir),
LOCAL_VALIDATE_TEST(relay_with_hidden_services),
+ LOCAL_VALIDATE_TEST(listen_ports),
LOCAL_VALIDATE_TEST(transproxy),
LOCAL_VALIDATE_TEST(exclude_nodes),
LOCAL_VALIDATE_TEST(node_families),
LOCAL_VALIDATE_TEST(token_bucket),
- LOCAL_VALIDATE_TEST(recommended_packages),
LOCAL_VALIDATE_TEST(fetch_dir),
LOCAL_VALIDATE_TEST(conn_limit),
LOCAL_VALIDATE_TEST(paths_needed),
@@ -4233,5 +4339,10 @@ struct testcase_t options_tests[] = {
LOCAL_VALIDATE_TEST(virtual_addr),
LOCAL_VALIDATE_TEST(testing_options),
LOCAL_VALIDATE_TEST(accel),
+ { "init_logs/granularity", test_options_init_logs_granularity, TT_FORK,
+ NULL, NULL },
+ { "init_logs/quiet", test_options_init_logs_quiet, TT_FORK,
+ NULL, NULL },
+ { "trial_assign", test_options_trial_assign, TT_FORK, NULL, NULL },
END_OF_TESTCASES /* */
};
diff --git a/src/test/test_options_act.c b/src/test/test_options_act.c
new file mode 100644
index 0000000000..942584bffd
--- /dev/null
+++ b/src/test/test_options_act.c
@@ -0,0 +1,272 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CONFIG_PRIVATE
+#include "core/or/or.h"
+#include "app/config/config.h"
+#include "lib/encoding/confline.h"
+
+#include "test/test.h"
+#include "test/log_test_helpers.h"
+#include "test/test_helpers.h"
+
+#ifndef _WIN32
+#include <sys/stat.h>
+
+/**
+ * Check whether fname is readable. On success set
+ * *<b>is_group_readable_out</b> to as appropriate and return 0. On failure
+ * return -1.
+ */
+static int
+get_file_mode(const char *fname, unsigned *permissions_out)
+{
+ struct stat st;
+ int r = stat(fname, &st);
+ if (r < 0)
+ return -1;
+ *permissions_out = (unsigned) st.st_mode;
+ return 0;
+}
+#define assert_mode(fn,mask,expected) STMT_BEGIN \
+ unsigned mode_; \
+ int tmp_ = get_file_mode((fn), &mode_); \
+ if (tmp_ < 0) { \
+ TT_DIE(("Couldn't stat %s: %s", (fn), strerror(errno))); \
+ } \
+ if ((mode_ & (mask)) != (expected)) { \
+ TT_DIE(("Bad mode %o on %s", mode_, (fn))); \
+ } \
+ STMT_END
+#else /* defined(_WIN32) */
+/* "group-readable" isn't meaningful on windows */
+#define assert_mode(fn,mask,expected) STMT_NIL
+#endif /* !defined(_WIN32) */
+
+static or_options_t *mock_opts;
+static const or_options_t *
+mock_get_options(void)
+{
+ return mock_opts;
+}
+
+static void
+test_options_act_create_dirs(void *arg)
+{
+ (void)arg;
+ MOCK(get_options, mock_get_options);
+ char *msg = NULL;
+ or_options_t *opts = mock_opts = options_new();
+
+ /* We're testing options_create_directories(), which assumes that
+ validate_data_directories() has already been called, and all of
+ KeyDirectory, DataDirectory, and CacheDirectory are set. */
+
+ /* Success case 1: all directories are the default */
+ char *fn;
+ fn = tor_strdup(get_fname_rnd("ddir"));
+ opts->DataDirectory = tor_strdup(fn);
+ opts->CacheDirectory = tor_strdup(fn);
+ tor_asprintf(&opts->KeyDirectory, "%s/keys", fn);
+ opts->DataDirectoryGroupReadable = 1;
+ opts->CacheDirectoryGroupReadable = -1; /* default. */
+ int r = options_create_directories(&msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
+ assert_mode(opts->DataDirectory, 0777, 0750);
+ assert_mode(opts->KeyDirectory, 0777, 0700);
+ tor_free(fn);
+ tor_free(opts->KeyDirectory);
+ or_options_free(opts);
+
+ /* Success case 2: all directories are different. */
+ opts = mock_opts = options_new();
+ opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
+ opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
+ opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
+ opts->CacheDirectoryGroupReadable = 1; // cache directory group readable
+ r = options_create_directories(&msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
+ assert_mode(opts->DataDirectory, 0777, 0700);
+ assert_mode(opts->KeyDirectory, 0777, 0700);
+ assert_mode(opts->CacheDirectory, 0777, 0750);
+ tor_free(fn);
+ or_options_free(opts);
+
+ /* Success case 3: all directories are the same. */
+ opts = mock_opts = options_new();
+ fn = tor_strdup(get_fname_rnd("ddir"));
+ opts->DataDirectory = tor_strdup(fn);
+ opts->CacheDirectory = tor_strdup(fn);
+ opts->KeyDirectory = tor_strdup(fn);
+ opts->DataDirectoryGroupReadable = 1;
+ opts->CacheDirectoryGroupReadable = -1; /* default. */
+ opts->KeyDirectoryGroupReadable = -1; /* default */
+ r = options_create_directories(&msg);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(msg, OP_EQ, NULL);
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
+ tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
+ assert_mode(opts->DataDirectory, 0777, 0750);
+ assert_mode(opts->KeyDirectory, 0777, 0750);
+ assert_mode(opts->CacheDirectory, 0777, 0750);
+ tor_free(fn);
+ or_options_free(opts);
+
+ /* Failure case 1: Can't make datadir. */
+ opts = mock_opts = options_new();
+ opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
+ opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
+ opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
+ write_str_to_file(opts->DataDirectory, "foo", 0);
+ r = options_create_directories(&msg);
+ tt_int_op(r, OP_LT, 0);
+ tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
+ or_options_free(opts);
+ tor_free(msg);
+
+ /* Failure case 2: Can't make keydir. */
+ opts = mock_opts = options_new();
+ opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
+ opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
+ opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
+ write_str_to_file(opts->KeyDirectory, "foo", 0);
+ r = options_create_directories(&msg);
+ tt_int_op(r, OP_LT, 0);
+ tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
+ or_options_free(opts);
+ tor_free(msg);
+
+ /* Failure case 3: Can't make cachedir. */
+ opts = mock_opts = options_new();
+ opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
+ opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
+ opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
+ write_str_to_file(opts->CacheDirectory, "foo", 0);
+ r = options_create_directories(&msg);
+ tt_int_op(r, OP_LT, 0);
+ tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
+ tor_free(fn);
+ or_options_free(opts);
+ tor_free(msg);
+
+ done:
+ UNMOCK(get_options);
+ or_options_free(opts);
+ mock_opts = NULL;
+ tor_free(fn);
+ tor_free(msg);
+}
+
+static void
+test_options_act_log_transition(void *arg)
+{
+ (void)arg;
+ or_options_t *opts = mock_opts = options_new();
+ or_options_t *old_opts = NULL;
+ opts->LogTimeGranularity = 1000;
+ opts->SafeLogging_ = SAFELOG_SCRUB_ALL;
+ struct log_transaction_t *lt = NULL;
+ char *msg = NULL;
+ MOCK(get_options, mock_get_options);
+
+ tt_ptr_op(opts->Logs, OP_EQ, NULL);
+ config_line_append(&opts->Logs, "Log", "notice stdout");
+ lt = options_start_log_transaction(NULL, &msg);
+ tt_assert(lt);
+ tt_assert(!msg);
+
+ // commit, see that there is a change.
+ options_commit_log_transaction(lt);
+ lt=NULL;
+ tt_int_op(get_min_log_level(), OP_EQ, LOG_NOTICE);
+
+ // Now drop to debug.
+ old_opts = opts;
+ opts = mock_opts = options_new();
+ opts->LogTimeGranularity = 1000;
+ opts->SafeLogging_ = SAFELOG_SCRUB_ALL;
+ config_line_append(&opts->Logs, "Log", "debug stdout");
+ lt = options_start_log_transaction(old_opts, &msg);
+ tt_assert(lt);
+ tt_assert(!msg);
+
+ setup_full_capture_of_logs(LOG_NOTICE);
+ options_commit_log_transaction(lt);
+ lt=NULL;
+ expect_single_log_msg_containing("may contain sensitive information");
+ tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
+
+ // Turn off SafeLogging
+ or_options_free(old_opts);
+ mock_clean_saved_logs();
+ old_opts = opts;
+ opts = mock_opts = options_new();
+ opts->SafeLogging_ = SAFELOG_SCRUB_NONE;
+ opts->LogTimeGranularity = 1000;
+ config_line_append(&opts->Logs, "Log", "debug stdout");
+ lt = options_start_log_transaction(old_opts, &msg);
+ tt_assert(lt);
+ tt_assert(!msg);
+ options_commit_log_transaction(lt);
+ lt=NULL;
+ expect_single_log_msg_containing("may contain sensitive information");
+ tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
+
+ // Try rolling back.
+ or_options_free(old_opts);
+ mock_clean_saved_logs();
+ old_opts = opts;
+ opts = mock_opts = options_new();
+ opts->SafeLogging_ = SAFELOG_SCRUB_NONE;
+ opts->LogTimeGranularity = 1000;
+ config_line_append(&opts->Logs, "Log", "notice stdout");
+ lt = options_start_log_transaction(old_opts, &msg);
+ tt_assert(lt);
+ tt_assert(!msg);
+ options_rollback_log_transaction(lt);
+ expect_no_log_entry();
+ lt = NULL;
+ tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
+
+ // Now try some bad options.
+ or_options_free(opts);
+ mock_clean_saved_logs();
+ opts = mock_opts = options_new();
+ opts->LogTimeGranularity = 1000;
+ config_line_append(&opts->Logs, "Log", "warn blaznert");
+ lt = options_start_log_transaction(old_opts, &msg);
+ tt_assert(!lt);
+ tt_str_op(msg, OP_EQ, "Failed to init Log options. See logs for details.");
+ expect_single_log_msg_containing("Couldn't parse");
+ tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
+
+ done:
+ UNMOCK(get_options);
+ or_options_free(opts);
+ or_options_free(old_opts);
+ tor_free(msg);
+ if (lt)
+ options_rollback_log_transaction(lt);
+ teardown_capture_of_logs();
+}
+
+#ifndef COCCI
+#define T(name) { #name, test_options_act_##name, TT_FORK, NULL, NULL }
+#endif
+
+struct testcase_t options_act_tests[] = {
+ T(create_dirs),
+ T(log_transition),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_parsecommon.c b/src/test/test_parsecommon.c
new file mode 100644
index 0000000000..9c22266da1
--- /dev/null
+++ b/src/test/test_parsecommon.c
@@ -0,0 +1,594 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "core/or/or.h"
+#include "test/test.h"
+#include "lib/memarea/memarea.h"
+#include "lib/encoding/binascii.h"
+#include "feature/dirparse/parsecommon.h"
+#include "test/log_test_helpers.h"
+
+static void
+test_parsecommon_tokenize_string_null(void *arg)
+{
+
+ memarea_t *area = memarea_new();
+ smartlist_t *tokens = smartlist_new();
+
+ (void)arg;
+
+ const char *str_with_null = "a\0bccccccccc";
+
+ int retval =
+ tokenize_string(area, str_with_null,
+ str_with_null + 3,
+ tokens, NULL, 0);
+
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ memarea_drop_all(area);
+ smartlist_free(tokens);
+ return;
+}
+
+static void
+test_parsecommon_tokenize_string_multiple_lines(void *arg)
+{
+ memarea_t *area = memarea_new();
+ smartlist_t *tokens = smartlist_new();
+
+ (void)arg;
+
+ token_rule_t table[] = {
+ T01("uptime", K_UPTIME, GE(1), NO_OBJ),
+ T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ),
+ T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ),
+ END_OF_TABLE,
+ };
+
+ char *str = tor_strdup(
+ "hibernating 0\nuptime 1024\n"
+ "published 2018-10-15 10:00:00\n");
+
+ int retval =
+ tokenize_string(area, str, NULL,
+ tokens, table, 0);
+
+ tt_int_op(smartlist_len(tokens), OP_EQ, 3);
+ directory_token_t *token = smartlist_get(tokens, 0);
+
+ tt_int_op(token->tp, OP_EQ, K_HIBERNATING);
+
+ token = smartlist_get(tokens, 1);
+
+ tt_int_op(token->tp, OP_EQ, K_UPTIME);
+
+ token = smartlist_get(tokens, 2);
+
+ tt_int_op(token->tp, OP_EQ, K_PUBLISHED);
+
+ tt_int_op(retval, OP_EQ, 0);
+
+ done:
+ tor_free(str);
+ memarea_drop_all(area);
+ smartlist_free(tokens);
+ return;
+}
+
+static void
+test_parsecommon_tokenize_string_min_cnt(void *arg)
+{
+ memarea_t *area = memarea_new();
+ smartlist_t *tokens = smartlist_new();
+
+ (void)arg;
+
+ token_rule_t table[] = {
+ T01("uptime", K_UPTIME, EQ(2), NO_OBJ),
+ T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ),
+ END_OF_TABLE,
+ };
+
+ // Missing "uptime"
+ char *str = tor_strdup("uptime 1024\nhibernating 0\n");
+
+ int retval =
+ tokenize_string(area, str, NULL,
+ tokens, table, 0);
+
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ tor_free(str);
+ memarea_drop_all(area);
+ smartlist_free(tokens);
+ return;
+}
+
+static void
+test_parsecommon_tokenize_string_max_cnt(void *arg)
+{
+ memarea_t *area = memarea_new();
+ smartlist_t *tokens = smartlist_new();
+
+ (void)arg;
+
+ token_rule_t table[] = {
+ T01("uptime", K_UPTIME, EQ(1), NO_OBJ),
+ T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ),
+ END_OF_TABLE,
+ };
+
+ // "uptime" expected once, but occurs twice in input.
+ char *str = tor_strdup(
+ "uptime 1024\nuptime 2048\nhibernating 0\n");
+
+ int retval =
+ tokenize_string(area, str, NULL,
+ tokens, table, 0);
+
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ tor_free(str);
+ memarea_drop_all(area);
+ smartlist_free(tokens);
+ return;
+}
+
+static void
+test_parsecommon_tokenize_string_at_start(void *arg)
+{
+ memarea_t *area = memarea_new();
+ smartlist_t *tokens = smartlist_new();
+
+ (void)arg;
+
+ token_rule_t table[] = {
+ T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
+ T01("uptime", K_UPTIME, EQ(1), NO_OBJ),
+ END_OF_TABLE,
+ };
+
+ // "client-name" is not the first line.
+ char *str = tor_strdup(
+ "uptime 1024\nclient-name Alice\n");
+
+ int retval =
+ tokenize_string(area, str, NULL, tokens, table, 0);
+
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ tor_free(str);
+ memarea_drop_all(area);
+ smartlist_free(tokens);
+ return;
+}
+
+static void
+test_parsecommon_tokenize_string_at_end(void *arg)
+{
+ memarea_t *area = memarea_new();
+ smartlist_t *tokens = smartlist_new();
+
+ (void)arg;
+
+ token_rule_t table[] = {
+ T1_END("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
+ T01("uptime", K_UPTIME, EQ(1), NO_OBJ),
+ END_OF_TABLE,
+ };
+
+ // "client-name" is not the last line.
+ char *str = tor_strdup(
+ "client-name Alice\nuptime 1024\n");
+
+ int retval =
+ tokenize_string(area, str, NULL, tokens, table, 0);
+
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ tor_free(str);
+ memarea_drop_all(area);
+ smartlist_free(tokens);
+ return;
+}
+
+static void
+test_parsecommon_tokenize_string_no_annotations(void *arg)
+{
+ memarea_t *area = memarea_new();
+ smartlist_t *tokens = smartlist_new();
+
+ (void)arg;
+
+ token_rule_t table[] = {
+ A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ),
+ END_OF_TABLE,
+ };
+
+ char *str = tor_strdup("@last-listed 2018-09-21 15:30:03\n");
+
+ int retval =
+ tokenize_string(area, str, NULL, tokens, table, 0);
+
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ tor_free(str);
+ memarea_drop_all(area);
+ smartlist_free(tokens);
+ return;
+}
+
+static void
+test_parsecommon_get_next_token_success(void *arg)
+{
+ memarea_t *area = memarea_new();
+ const char *str = "uptime 1024";
+ const char *end = str + strlen(str);
+ const char **s = &str;
+ token_rule_t table = T01("uptime", K_UPTIME, GE(1), NO_OBJ);
+ (void)arg;
+
+ directory_token_t *token = get_next_token(area, s, end, &table);
+
+ tt_int_op(token->tp, OP_EQ, K_UPTIME);
+ tt_int_op(token->n_args, OP_EQ, 1);
+ tt_str_op(*(token->args), OP_EQ, "1024");
+ tt_assert(!token->object_type);
+ tt_int_op(token->object_size, OP_EQ, 0);
+ tt_assert(!token->object_body);
+
+ tt_ptr_op(*s, OP_EQ, end);
+
+ done:
+ memarea_drop_all(area);
+ return;
+}
+
+static void
+test_parsecommon_get_next_token_concat_args(void *arg)
+{
+ memarea_t *area = memarea_new();
+ const char *str = "proto A=1 B=2";
+ const char *end = str + strlen(str);
+ const char **s = &str;
+ token_rule_t rule = T01("proto", K_PROTO, CONCAT_ARGS, NO_OBJ);
+ (void)arg;
+
+ directory_token_t *token = get_next_token(area, s, end, &rule);
+
+ tt_int_op(token->tp, OP_EQ, K_PROTO);
+ tt_int_op(token->n_args, OP_EQ, 1);
+ tt_str_op(*(token->args), OP_EQ, "A=1 B=2");
+
+ done:
+ memarea_drop_all(area);
+}
+
+static void
+test_parsecommon_get_next_token_parse_keys(void *arg)
+{
+ (void)arg;
+
+ memarea_t *area = memarea_new();
+ const char *str =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMDdIya33BfNlHOkzoTKSTT8EjD64waMfUr372syVHiFjHhObwKwGA5u\n"
+ "sHaMIe9r+Ij/4C1dKyuXkcz3DOl6gWNhTD7dZ89I+Okoh1jWe30jxCiAcywC22p5\n"
+ "XLhrDkX1A63Z7XCH9ltwU2WMqWsVM98N2GR6MTujP7wtqdLExYN1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n";
+
+ const char *end = str + strlen(str);
+ const char **s = (const char **)&str;
+ directory_token_t *token = NULL;
+ directory_token_t *token2 = NULL;
+
+ token_rule_t rule = T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024);
+
+ token = get_next_token(area, s, end, &rule);
+ tt_assert(token);
+
+ tt_int_op(token->tp, OP_EQ, R_IPO_ONION_KEY);
+ tt_int_op(token->n_args, OP_EQ, 0);
+ tt_str_op(token->object_type, OP_EQ, "RSA PUBLIC KEY");
+ tt_int_op(token->object_size, OP_EQ, 140);
+ tt_assert(token->object_body);
+ tt_assert(token->key);
+ tt_assert(!token->error);
+
+ const char *str2 =
+ "client-key\n"
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIICXAIBAAKBgQCwS810a2auH2PQchOBz9smNgjlDu31aq0IYlUohSYbhcv5AJ+d\n"
+ "DY0nfZWzS+mZPwzL3UiEnTt6PVv7AgoZ5V9ZJWJTKIURjJpkK0mstfJKHKIZhf84\n"
+ "pmFfRej9GQViB6NLtp1obOXJgJixSlMfw9doDI4NoAnEISCyH/tD77Qs2wIDAQAB\n"
+ "AoGAbDg8CKkdQOnX9c7xFpCnsE8fKqz9eddgHHNwXw1NFTwOt+2gDWKSMZmv2X5S\n"
+ "CVZg3owZxf5W0nT0D6Ny2+6nliak7foYAvkD0BsCiBhgftwC0zAo6k5rIbUKB3PJ\n"
+ "QLFXgpJhqWuXkODyt/hS/GTernR437WVSEGp1bnALqiFabECQQDaqHOxzoWY/nvH\n"
+ "KrfUi8EhqCnqERlRHwrW0MQZ1RPvF16OPPma+xa+ht/amfh3vYN5tZY82Zm43gGl\n"
+ "XWL5cZhNAkEAzmdSootYVnqLLLRMfHKXnO1XbaEcA/08MDNKGlSclBJixFenE8jX\n"
+ "iQsUbHwMJuGONvzWpRGPBP2f8xBd28ZtxwJARY+LZshtpfNniz/ixYJESaHG28je\n"
+ "xfjbKOW3TQSFV+2WTifFvHEeljQwKMoMyoMGvYRwLCGJjs9JtMLVxsdFjQJBAKwD\n"
+ "3BBvBQ39TuPQ1zWX4tb7zjMlY83HTFP3Sriq71tP/1QWoL2SUl56B2lp8E6vB/C3\n"
+ "wsMK4SCNprHRYAd7VZ0CQDKn6Zhd11P94PLs0msybFEh1VXr6CEW/BrxBgbL4ls6\n"
+ "dbX5XO0z4Ra8gYXgObgimhyMDYO98Idt5+Z3HIdyrSc=\n"
+ "-----END RSA PRIVATE KEY-----\n";
+
+ const char *end2 = str2 + strlen(str2);
+ const char **s2 = (const char **)&str2;
+
+ token_rule_t rule2 = T01("client-key", C_CLIENT_KEY, NO_ARGS,
+ NEED_SKEY_1024);
+
+ token2 = get_next_token(area, s2, end2, &rule2);
+ tt_assert(token2);
+
+ tt_int_op(token2->tp, OP_EQ, C_CLIENT_KEY);
+ tt_int_op(token2->n_args, OP_EQ, 0);
+ tt_str_op(token2->object_type, OP_EQ, "RSA PRIVATE KEY");
+ tt_int_op(token2->object_size, OP_EQ, 608);
+ tt_assert(token2->object_body);
+ tt_assert(token2->key);
+ tt_assert(!token->error);
+
+ done:
+ if (token) token_clear(token);
+ if (token2) token_clear(token2);
+ memarea_drop_all(area);
+}
+
+static void
+test_parsecommon_get_next_token_object(void *arg)
+{
+ memarea_t *area = memarea_new();
+
+ const char *str =
+ "directory-signature 0232AF901C31A04EE9848595AF9BB7620D4C5B2E "
+ "CD1FD971855430880D3C31E0331C5C55800C2F79\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "dLTbc1Lad/OWKBJhA/dERzDHumswTAzBFAWAz2vnQhLsebs1SOm0W/vceEsiEkiF\n"
+ "A+JJSzIyfywJc6Mnk7aKMEIFjOO/MaxuAp4zv+q+JonJkF0ExjMqvKR0D6pSFmfN\n"
+ "cnemnxGHxNuPDnKl0imbWKmWDsHtwgi4zWeTq3MekfMOXKi6gIh+bDFzCs9/Vquh\n"
+ "uNKJI1jW/A2DEKeaSAODEv9VoCsYSvbVVEuHCBWjeNAurd5aL26BrAolW6m7pkD6\n"
+ "I+cQ8dQG6Wa/Zt6gLXtBbOP2o/iDI7ahDP9diNkBI/rm4nfp9j4piTwsqpi7xz9J\n"
+ "Ua9DEZB9KbJHVX1rGShrLA==\n"
+ "-----END SIGNATURE-----\n";
+
+ const char *end = str + strlen(str);
+ const char **s = &str;
+ token_rule_t rule = T("directory-signature", K_DIRECTORY_SIGNATURE,
+ GE(2), NEED_OBJ);
+ (void)arg;
+
+ directory_token_t *token = get_next_token(area, s, end, &rule);
+
+ tt_int_op(token->tp, OP_EQ, K_DIRECTORY_SIGNATURE);
+ tt_int_op(token->n_args, OP_EQ, 2);
+ tt_str_op(token->args[0], OP_EQ,
+ "0232AF901C31A04EE9848595AF9BB7620D4C5B2E");
+ tt_str_op(token->args[1], OP_EQ,
+ "CD1FD971855430880D3C31E0331C5C55800C2F79");
+
+ tt_assert(!token->error);
+
+ char decoded[256];
+ const char *signature =
+ "dLTbc1Lad/OWKBJhA/dERzDHumswTAzBFAWAz2vnQhLsebs1SOm0W/vceEsiEkiF\n"
+ "A+JJSzIyfywJc6Mnk7aKMEIFjOO/MaxuAp4zv+q+JonJkF0ExjMqvKR0D6pSFmfN\n"
+ "cnemnxGHxNuPDnKl0imbWKmWDsHtwgi4zWeTq3MekfMOXKi6gIh+bDFzCs9/Vquh\n"
+ "uNKJI1jW/A2DEKeaSAODEv9VoCsYSvbVVEuHCBWjeNAurd5aL26BrAolW6m7pkD6\n"
+ "I+cQ8dQG6Wa/Zt6gLXtBbOP2o/iDI7ahDP9diNkBI/rm4nfp9j4piTwsqpi7xz9J\n"
+ "Ua9DEZB9KbJHVX1rGShrLA==\n";
+ tt_assert(signature);
+ size_t signature_len = strlen(signature);
+ base64_decode(decoded, sizeof(decoded), signature, signature_len);
+
+ tt_str_op(token->object_type, OP_EQ, "SIGNATURE");
+ tt_int_op(token->object_size, OP_EQ, 256);
+ tt_mem_op(token->object_body, OP_EQ, decoded, 256);
+
+ tt_assert(!token->key);
+
+ done:
+ memarea_drop_all(area);
+}
+
+static void
+test_parsecommon_get_next_token_err_too_many_args(void *arg)
+{
+ memarea_t *area = memarea_new();
+ const char *str = "uptime 1024 1024 1024";
+ const char *end = str + strlen(str);
+ const char **s = &str;
+ token_rule_t table = T01("uptime", K_UPTIME, EQ(1), NO_OBJ);
+ (void)arg;
+
+ directory_token_t *token = get_next_token(area, s, end, &table);
+
+ tt_int_op(token->tp, OP_EQ, ERR_);
+ tt_str_op(token->error, OP_EQ, "Too many arguments to uptime");
+
+ done:
+ memarea_drop_all(area);
+ return;
+}
+
+static void
+test_parsecommon_get_next_token_err_too_few_args(void *arg)
+{
+ memarea_t *area = memarea_new();
+ const char *str = "uptime";
+ const char *end = str + strlen(str);
+ const char **s = &str;
+ token_rule_t table = T01("uptime", K_UPTIME, EQ(1), NO_OBJ);
+ (void)arg;
+
+ directory_token_t *token = get_next_token(area, s, end, &table);
+
+ tt_int_op(token->tp, OP_EQ, ERR_);
+ tt_str_op(token->error, OP_EQ, "Too few arguments to uptime");
+
+ done:
+ memarea_drop_all(area);
+ return;
+}
+
+static void
+test_parsecommon_get_next_token_err_obj_missing_endline(void *arg)
+{
+ memarea_t *area = memarea_new();
+
+ const char *str =
+ "directory-signature 0232AF901C31A04EE9848595AF9BB7620D4C5B2E "
+ "CD1FD971855430880D3C31E0331C5C55800C2F79\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "dLTbc1Lad/OWKBJhA/dERzDHumswTAzBFAWAz2vnQhLsebs1SOm0W/vceEsiEkiF\n"
+ "A+JJSzIyfywJc6Mnk7aKMEIFjOO/MaxuAp4zv+q+JonJkF0ExjMqvKR0D6pSFmfN\n"
+ "cnemnxGHxNuPDnKl0imbWKmWDsHtwgi4zWeTq3MekfMOXKi6gIh+bDFzCs9/Vquh\n"
+ "uNKJI1jW/A2DEKeaSAODEv9VoCsYSvbVVEuHCBWjeNAurd5aL26BrAolW6m7pkD6\n"
+ "I+cQ8dQG6Wa/Zt6gLXtBbOP2o/iDI7ahDP9diNkBI/rm4nfp9j4piTwsqpi7xz9J\n"
+ "Ua9DEZB9KbJHVX1rGShrLA==\n";
+
+ const char *end = str + strlen(str);
+ const char **s = &str;
+ token_rule_t rule = T("directory-signature", K_DIRECTORY_SIGNATURE,
+ GE(2), NEED_OBJ);
+ (void)arg;
+
+ directory_token_t *token = get_next_token(area, s, end, &rule);
+
+ tt_int_op(token->tp, OP_EQ, ERR_);
+ tt_str_op(token->error, OP_EQ, "Malformed object: missing object end line");
+
+ done:
+ memarea_drop_all(area);
+ return;
+}
+
+static void
+test_parsecommon_get_next_token_err_bad_beginline(void *arg)
+{
+ memarea_t *area = memarea_new();
+
+ const char *str =
+ "directory-signature 0232AF901C31A04EE9848595AF9BB7620D4C5B2E "
+ "CD1FD971855430880D3C31E0331C5C55800C2F79\n"
+ "-----BEGIN SIGNATURE-Z---\n"
+ "dLTbc1Lad/OWKBJhA/dERzDHumswTAzBFAWAz2vnQhLsebs1SOm0W/vceEsiEkiF\n"
+ "A+JJSzIyfywJc6Mnk7aKMEIFjOO/MaxuAp4zv+q+JonJkF0ExjMqvKR0D6pSFmfN\n"
+ "cnemnxGHxNuPDnKl0imbWKmWDsHtwgi4zWeTq3MekfMOXKi6gIh+bDFzCs9/Vquh\n"
+ "uNKJI1jW/A2DEKeaSAODEv9VoCsYSvbVVEuHCBWjeNAurd5aL26BrAolW6m7pkD6\n"
+ "I+cQ8dQG6Wa/Zt6gLXtBbOP2o/iDI7ahDP9diNkBI/rm4nfp9j4piTwsqpi7xz9J\n"
+ "Ua9DEZB9KbJHVX1rGShrLA==\n"
+ "-----END SIGNATURE-----\n";
+
+ const char *end = str + strlen(str);
+ const char **s = &str;
+ token_rule_t rule = T("directory-signature", K_DIRECTORY_SIGNATURE,
+ GE(2), NEED_OBJ);
+ (void)arg;
+
+ directory_token_t *token = get_next_token(area, s, end, &rule);
+
+ tt_int_op(token->tp, OP_EQ, ERR_);
+ tt_str_op(token->error, OP_EQ, "Malformed object: bad begin line");
+
+ done:
+ memarea_drop_all(area);
+ return;
+}
+
+static void
+test_parsecommon_get_next_token_err_tag_mismatch(void *arg)
+{
+ memarea_t *area = memarea_new();
+
+ const char *str =
+ "directory-signature 0232AF901C31A04EE9848595AF9BB7620D4C5B2E "
+ "CD1FD971855430880D3C31E0331C5C55800C2F79\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "dLTbc1Lad/OWKBJhA/dERzDHumswTAzBFAWAz2vnQhLsebs1SOm0W/vceEsiEkiF\n"
+ "A+JJSzIyfywJc6Mnk7aKMEIFjOO/MaxuAp4zv+q+JonJkF0ExjMqvKR0D6pSFmfN\n"
+ "cnemnxGHxNuPDnKl0imbWKmWDsHtwgi4zWeTq3MekfMOXKi6gIh+bDFzCs9/Vquh\n"
+ "uNKJI1jW/A2DEKeaSAODEv9VoCsYSvbVVEuHCBWjeNAurd5aL26BrAolW6m7pkD6\n"
+ "I+cQ8dQG6Wa/Zt6gLXtBbOP2o/iDI7ahDP9diNkBI/rm4nfp9j4piTwsqpi7xz9J\n"
+ "Ua9DEZB9KbJHVX1rGShrLA==\n"
+ "-----END SOMETHINGELSE-----\n";
+
+ const char *end = str + strlen(str);
+ const char **s = &str;
+ token_rule_t rule = T("directory-signature", K_DIRECTORY_SIGNATURE,
+ GE(2), NEED_OBJ);
+ (void)arg;
+
+ directory_token_t *token = get_next_token(area, s, end, &rule);
+
+ tt_int_op(token->tp, OP_EQ, ERR_);
+ tt_str_op(token->error, OP_EQ,
+ "Malformed object: mismatched end tag SIGNATURE");
+
+ done:
+ memarea_drop_all(area);
+ return;
+}
+
+static void
+test_parsecommon_get_next_token_err_bad_base64(void *arg)
+{
+ memarea_t *area = memarea_new();
+
+ const char *str =
+ "directory-signature 0232AF901C31A04EE9848595AF9BB7620D4C5B2E "
+ "CD1FD971855430880D3C31E0331C5C55800C2F79\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "%%@%%%%%%%!!!'\n"
+ "-----END SIGNATURE-----\n";
+
+ const char *end = str + strlen(str);
+ const char **s = &str;
+ token_rule_t rule = T("directory-signature", K_DIRECTORY_SIGNATURE,
+ GE(2), NEED_OBJ);
+ (void)arg;
+
+ directory_token_t *token = get_next_token(area, s, end, &rule);
+
+ tt_int_op(token->tp, OP_EQ, ERR_);
+ tt_str_op(token->error, OP_EQ, "Malformed object: bad base64-encoded data");
+
+ done:
+ memarea_drop_all(area);
+ return;
+}
+
+#define PARSECOMMON_TEST(name) \
+ { #name, test_parsecommon_ ## name, 0, NULL, NULL }
+
+struct testcase_t parsecommon_tests[] = {
+ PARSECOMMON_TEST(tokenize_string_null),
+ PARSECOMMON_TEST(tokenize_string_multiple_lines),
+ PARSECOMMON_TEST(tokenize_string_min_cnt),
+ PARSECOMMON_TEST(tokenize_string_max_cnt),
+ PARSECOMMON_TEST(tokenize_string_at_start),
+ PARSECOMMON_TEST(tokenize_string_at_end),
+ PARSECOMMON_TEST(tokenize_string_no_annotations),
+ PARSECOMMON_TEST(get_next_token_success),
+ PARSECOMMON_TEST(get_next_token_concat_args),
+ PARSECOMMON_TEST(get_next_token_parse_keys),
+ PARSECOMMON_TEST(get_next_token_object),
+ PARSECOMMON_TEST(get_next_token_err_too_many_args),
+ PARSECOMMON_TEST(get_next_token_err_too_few_args),
+ PARSECOMMON_TEST(get_next_token_err_obj_missing_endline),
+ PARSECOMMON_TEST(get_next_token_err_bad_beginline),
+ PARSECOMMON_TEST(get_next_token_err_tag_mismatch),
+ PARSECOMMON_TEST(get_next_token_err_bad_base64),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_parseconf.sh b/src/test/test_parseconf.sh
new file mode 100755
index 0000000000..c02b8b23c0
--- /dev/null
+++ b/src/test/test_parseconf.sh
@@ -0,0 +1,655 @@
+#!/bin/sh
+# Copyright 2019, The Tor Project, Inc.
+# See LICENSE for licensing information
+
+# Integration test script for verifying that Tor configurations are parsed as
+# we expect.
+#
+# Valid configurations are tested with --dump-config, which parses and
+# validates the configuration before writing it out. We then make sure that
+# the result is what we expect, before parsing and dumping it again to make
+# sure that there is no change. Optionally, we can also test the log messages
+# with --verify-config.
+#
+# Invalid configurations are tested with --verify-config, which parses
+# and validates the configuration. We capture its output and make sure that
+# it contains the error message we expect.
+#
+# When tor is compiled with different libraries or modules, some
+# configurations may have different results. We can specify these result
+# variants using additional result files.
+
+# This script looks for its test cases as individual directories in
+# src/test/conf_examples/. Each test may have these files:
+#
+# Configuration Files
+#
+# torrc -- Usually needed. This file is passed to Tor on the command line
+# with the "-f" flag. (If you omit it, you'll test Tor's behavior when
+# it receives a nonexistent configuration file.)
+#
+# torrc.defaults -- Optional. If present, it is passed to Tor on the command
+# line with the --defaults-torrc option. If this file is absent, an empty
+# file is passed instead to prevent Tor from reading the system defaults.
+#
+# cmdline -- Optional. If present, it contains command-line arguments that
+# will be passed to Tor.
+#
+# (included torrc files or directories) -- Optional. Additional files can be
+# included in configuration, using the "%include" directive. Files or
+# directories can be included in any of the config files listed above.
+# Include paths should be specified relative to the test case directory.
+#
+# Result Files
+#
+# expected -- If this file is present, then it should be the expected result
+# of "--dump-config short" for this test case. Exactly one of
+# "expected" or "error" must be present, or the test will fail.
+#
+# expected_log -- Optional. If this file is present, then it contains a regex
+# that must be matched by some line in the output of "--verify-config",
+# which must succeed. Only used if "expected" is also present.
+#
+# error -- If this file is present, then it contains a regex that must be
+# matched by some line in the output of "--verify-config", which must
+# fail. Exactly one of "expected" or "error" must be present, or the
+# test will fail.
+#
+# {expected,expected_log,error}_${TOR_LIBS_ENABLED}* -- If this file is
+# present, then the outcome is different when some optional libraries are
+# enabled. If there is no result file matching the exact list of enabled
+# libraries, the script searches for result files with one or more of
+# those libraries disabled. The search terminates at the standard result
+# file. If expected* is present, the script also searches for
+# expected_log*.
+#
+# For example:
+# A test that succeeds, regardless of any enabled libraries:
+# - expected
+# A test that has a different result if the nss library is enabled
+# (but the same result if any other library is enabled). We also check
+# the log output in this test:
+# - expected
+# - expected_log
+# - expected_nss
+# - expected_log_nss
+# A test that fails if the lzma and zstd modules are *not* enabled:
+# - error
+# - expected_lzma_zstd
+#
+# {expected,expected_log,error}*_no_${TOR_MODULES_DISABLED} -- If this file is
+# present, then the outcome is different when some modules are disabled.
+# If there is no result file matching the exact list of disabled modules,
+# the standard result file is used. If expected* is present, the script
+# also searches for expected_log*.
+#
+# For example:
+# A test that succeeds, regardless of any disabled modules:
+# - expected
+# A test that has a different result if the relay module is disabled
+# (but the same result if just the dirauth module is disabled):
+# - expected
+# - expected_no_relay_dirauth
+# A test that fails if the dirauth module is disabled:
+# - expected
+# - error_no_dirauth
+# - error_no_relay_dirauth
+# (Disabling the relay module also disables dirauth module. But we don't
+# want to encode that knowledge in this test script, so we supply a
+# separate result file for every combination of disabled modules that
+# has a different result.)
+
+umask 077
+set -e
+
+MYNAME="$0"
+
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if test -d "$f"; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
+# find the tor binary
+if test $# -ge 1; then
+ TOR_BINARY="$1"
+ shift
+else
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "Using Tor binary '$TOR_BINARY'."
+
+# make a safe space for temporary files
+DATA_DIR=$(mktemp -d -t tor_parseconf_tests.XXXXXX)
+trap 'rm -rf "$DATA_DIR"' 0
+
+# This is where we look for examples
+EXAMPLEDIR="$(dirname "$0")"/conf_examples
+
+case "$(uname -s)" in
+ CYGWIN*) WINDOWS=1;;
+ MINGW*) WINDOWS=1;;
+ MSYS*) WINDOWS=1;;
+ *) WINDOWS=0;;
+esac
+
+####
+# BUG WORKAROUND FOR 31757:
+# On Appveyor, it seems that Tor sometimes randomly fails to produce
+# output with --dump-config. Whil we are figuring this out, do not treat
+# windows errors as hard failures.
+####
+if test "$WINDOWS" = 1; then
+ EXITCODE=0
+else
+ EXITCODE=1
+fi
+
+FINAL_EXIT=0
+NEXT_TEST=
+
+# Log a failure message to stderr, using $@ as a printf string and arguments
+# Set NEXT_TEST to "yes" and FINAL_EXIT to $EXITCODE.
+fail_printf()
+{
+ printf "FAIL: " >&2
+ # The first argument is a printf string, so this warning is spurious
+ # shellcheck disable=SC2059
+ printf "$@" >&2
+ NEXT_TEST="yes"
+ FINAL_EXIT=$EXITCODE
+}
+
+# Log a failure message to stderr, using $@ as a printf string and arguments
+# Exit with status $EXITCODE.
+die_printf()
+{
+ printf "FAIL: CRITICAL error in '%s':" "$MYNAME" >&2
+ # The first argument is a printf string, so this warning is spurious
+ # shellcheck disable=SC2059
+ printf "$@" >&2
+ exit $EXITCODE
+}
+
+if test "$WINDOWS" = 1; then
+ FILTER="dos2unix"
+else
+ FILTER="cat"
+fi
+
+EMPTY="${DATA_DIR}/EMPTY"
+touch "$EMPTY" || die_printf "Couldn't create empty file '%s'.\\n" \
+ "$EMPTY"
+NON_EMPTY="${DATA_DIR}/NON_EMPTY"
+echo "This pattern should not match any log messages" \
+ > "$NON_EMPTY" || die_printf "Couldn't create non-empty file '%s'.\\n" \
+ "$NON_EMPTY"
+
+STANDARD_LIBS="libevent\\|openssl\\|zlib"
+# Lib names are restricted to [a-z0-9]* at the moment
+# We don't actually want to support foreign accents here
+# shellcheck disable=SC2018,SC2019
+TOR_LIBS_ENABLED="$("$TOR_BINARY" --verify-config \
+ -f "$EMPTY" --defaults-torrc "$EMPTY" \
+ | sed -n 's/.* Tor .* running on .* with\(.*\) and .* .* as libc\./\1/p' \
+ | tr 'A-Z' 'a-z' | tr ',' '\n' \
+ | grep -v "$STANDARD_LIBS" | grep -v "n/a" \
+ | sed 's/\( and\)* \(lib\)*\([a-z0-9]*\) .*/\3/' \
+ | sort | tr '\n' '_')"
+# Remove the last underscore, if there is one
+TOR_LIBS_ENABLED=${TOR_LIBS_ENABLED%_}
+
+# If we ever have more than 3 optional libraries, we'll need more code here
+TOR_LIBS_ENABLED_COUNT="$(echo "$TOR_LIBS_ENABLED_SEARCH" \
+ | tr ' ' '\n' | wc -l)"
+if test "$TOR_LIBS_ENABLED_COUNT" -gt 3; then
+ die_printf "Can not handle more than 3 optional libraries.\\n"
+fi
+# Brute-force the combinations of libraries
+TOR_LIBS_ENABLED_SEARCH_3="$(echo "$TOR_LIBS_ENABLED" \
+ | sed -n \
+ 's/^\([^_]*\)_\([^_]*\)_\([^_]*\)$/_\1_\2 _\1_\3 _\2_\3 _\1 _\2 _\3/p')"
+TOR_LIBS_ENABLED_SEARCH_2="$(echo "$TOR_LIBS_ENABLED" \
+ | sed -n 's/^\([^_]*\)_\([^_]*\)$/_\1 _\2/p')"
+TOR_LIBS_ENABLED_SEARCH="_$TOR_LIBS_ENABLED \
+ $TOR_LIBS_ENABLED_SEARCH_3 \
+ $TOR_LIBS_ENABLED_SEARCH_2"
+TOR_LIBS_ENABLED_SEARCH="$(echo "$TOR_LIBS_ENABLED_SEARCH" | tr ' ' '\n' \
+ | grep -v '^_*$' | tr '\n' ' ')"
+
+TOR_MODULES_DISABLED="$("$TOR_BINARY" --list-modules | grep ': no' \
+ | cut -d ':' -f1 | sort | tr '\n' '_')"
+# Remove the last underscore, if there is one
+TOR_MODULES_DISABLED=${TOR_MODULES_DISABLED%_}
+
+echo "Tor is configured with:"
+echo "Optional Libraries: ${TOR_LIBS_ENABLED:-(None)}"
+if test "$TOR_LIBS_ENABLED"; then
+ echo "Optional Library Search List: $TOR_LIBS_ENABLED_SEARCH"
+fi
+echo "Disabled Modules: ${TOR_MODULES_DISABLED:-(None)}"
+
+# Yes, unix uses "0" for a successful command
+TRUE=0
+FALSE=1
+
+# Run tor --verify-config on the torrc $1, and defaults torrc $2, which may
+# be $EMPTY. Pass tor the extra command line arguments $3, which will be
+# passed unquoted.
+# Send tor's standard output to stderr.
+log_verify_config()
+{
+ # show the command we're about to execute
+ # log_verify_config() is only called when we've failed
+ printf "Tor --verify-config said:\\n" >&2
+ printf "$ %s %s %s %s %s %s %s\\n" \
+ "$TOR_BINARY" --verify-config \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ "$3" \
+ >&2
+ # We need cmdline unquoted
+ # shellcheck disable=SC2086
+ "$TOR_BINARY" --verify-config \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ $3 \
+ >&2 \
+ || true
+}
+
+# Run "tor --dump-config short" on the torrc $1, and defaults torrc $2, which
+# may be $EMPTY. Pass tor the extra command line arguments $3, which will be
+# passed unquoted. Send tor's standard output to $4.
+#
+# Set $FULL_TOR_CMD to the tor command line that was executed.
+#
+# If tor fails, fail_printf() using the file name $5, and context $6,
+# which may be an empty string. Then run log_verify_config().
+dump_config()
+{
+ if test "$6"; then
+ CONTEXT=" $6"
+ else
+ CONTEXT=""
+ fi
+
+ # keep the command we're about to execute, and show if it we fail
+ FULL_TOR_CMD=$(printf "$ %s %s %s %s %s %s %s %s" \
+ "$TOR_BINARY" --dump-config short \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ "$3"
+ )
+ # We need cmdline unquoted
+ # shellcheck disable=SC2086
+ if ! "$TOR_BINARY" --dump-config short \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ $3 \
+ > "$4"; then
+ fail_printf "'%s': Tor --dump-config reported an error%s:\\n%s\\n" \
+ "$5" \
+ "$CONTEXT" \
+ "$FULL_TOR_CMD"
+ log_verify_config "$1" \
+ "$2" \
+ "$3"
+ fi
+}
+
+# Run "$FILTER" on the input $1.
+# Send the standard output to $2.
+# If tor fails, log a failure message using the file name $3, and context $4,
+# which may be an empty string.
+filter()
+{
+ if test "$4"; then
+ CONTEXT=" $4"
+ else
+ CONTEXT=""
+ fi
+
+ "$FILTER" "$1" \
+ > "$2" \
+ || fail_printf "'%s': Filter '%s' reported an error%s.\\n" \
+ "$3" \
+ "$FILTER" \
+ "$CONTEXT"
+}
+
+# Compare the expected file $1, and output file $2.
+#
+# If they are different, fail. Log the differences between the files.
+# Run log_verify_config() with torrc $3, defaults torrc $4, and command
+# line $5, to log Tor's error messages.
+#
+# If the file contents are identical, returns true. Otherwise, return false.
+#
+# Log failure messages using fail_printf(), with the expected file name,
+# context $6, which may be an empty string, and the tor command line $7.
+check_diff()
+{
+ if test "$6"; then
+ CONTEXT=" $6"
+ else
+ CONTEXT=""
+ fi
+
+ if cmp "$1" "$2" > /dev/null; then
+ return "$TRUE"
+ else
+ fail_printf "'%s': Tor --dump-config said%s:\\n%s\\n" \
+ "$1" \
+ "$CONTEXT" \
+ "$7"
+ diff -u "$1" "$2" >&2 \
+ || true
+ log_verify_config "$3" \
+ "$4" \
+ "$5"
+ return "$FALSE"
+ fi
+}
+
+# Run "tor --dump-config short" on the torrc $1, and defaults torrc $2, which
+# may be $EMPTY. Pass tor the extra command line arguments $3, which will be
+# passed unquoted. Send tor's standard output to $4, after running $FILTER
+# on it.
+#
+# If tor fails, run log_verify_config().
+#
+# Compare the expected file $5, and output file. If they are different, fail.
+# If this is the first step that failed in this test, run log_verify_config().
+#
+# If the file contents are identical, returns true. Otherwise, return false,
+# and log the differences between the files.
+#
+# Log failure messages using fail_printf(), with the expected file name, and
+# context $6, which may be an empty string.
+check_dump_config()
+{
+ OUTPUT="$4"
+ OUTPUT_RAW="${OUTPUT}_raw"
+
+ FULL_TOR_CMD=
+ dump_config "$1" \
+ "$2" \
+ "$3" \
+ "$OUTPUT_RAW" \
+ "$5" \
+ "$6"
+
+ filter "$OUTPUT_RAW" \
+ "$OUTPUT" \
+ "$5" \
+ "$6"
+
+ if check_diff "$5" \
+ "$OUTPUT" \
+ "$1" \
+ "$2" \
+ "$3" \
+ "$6" \
+ "$FULL_TOR_CMD"; then
+ return "$TRUE"
+ else
+ return "$FALSE"
+ fi
+}
+
+# Check if $1 is an empty file.
+# If it is, fail_printf() using $2 as the type of file.
+# Returns true if the file is empty, false otherwise.
+check_empty_pattern()
+{
+ if ! test -s "$1"; then
+ fail_printf "%s file '%s' is empty, and will match any output.\\n" \
+ "$2" \
+ "$1"
+ return "$TRUE"
+ else
+ return "$FALSE"
+ fi
+}
+
+# Run tor --verify-config on the torrc $1, and defaults torrc $2, which may
+# be $EMPTY. Pass tor the extra command line arguments $3, which will be
+# passed unquoted. Send tor's standard output to $4.
+#
+# Set $FULL_TOR_CMD to the tor command line that was executed.
+#
+# If tor's exit status does not match the boolean $5, fail_printf()
+# using the file name $6, and context $7, which is required.
+verify_config()
+{
+ RESULT=$TRUE
+
+ # keep the command we're about to execute, and show if it we fail
+ FULL_TOR_CMD=$(printf "$ %s %s %s %s %s %s %s" \
+ "$TOR_BINARY" --verify-config \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ "$3"
+ )
+ # We need cmdline unquoted
+ # shellcheck disable=SC2086
+ "$TOR_BINARY" --verify-config \
+ -f "$1" \
+ --defaults-torrc "$2" \
+ $3 \
+ > "$4" || RESULT=$FALSE
+
+ # Convert the actual and expected results to boolean, and compare
+ if test $((! (! RESULT))) -ne $((! (! $5))); then
+ fail_printf "'%s': Tor --verify-config did not %s:\\n%s\\n" \
+ "$6" \
+ "$7" \
+ "$FULL_TOR_CMD"
+ cat "$4" >&2
+ fi
+}
+
+# Check for the patterns in the match file $1, in the output file $2.
+# Uses grep with the entire contents of the match file as the pattern.
+# (Not "grep -f".)
+#
+# If the pattern does not match any lines in the output file, fail.
+# Log the pattern, and the entire contents of the output file.
+#
+# Log failure messages using fail_printf(), with the match file name,
+# context $3, and tor command line $4, which are required.
+check_pattern()
+{
+ expect_log="$(cat "$1")"
+ if ! grep "$expect_log" "$2" > /dev/null; then
+ fail_printf "Expected %s '%s':\\n%s\\n" \
+ "$3" \
+ "$1" \
+ "$expect_log"
+ printf "Tor --verify-config said:\\n%s\\n" \
+ "$4" >&2
+ cat "$2" >&2
+ fi
+}
+
+# Run tor --verify-config on the torrc $1, and defaults torrc $2, which may
+# be $EMPTY. Pass tor the extra command line arguments $3, which will be
+# passed unquoted. Send tor's standard output to $4.
+#
+# If tor's exit status does not match the boolean $5, fail.
+#
+# Check for the patterns in the match file $6, in the output file.
+# Uses grep with the entire contents of the match file as the pattern.
+# (Not "grep -f".) The match file must not be empty.
+#
+# If the pattern does not match any lines in the output file, fail.
+# Log the pattern, and the entire contents of the output file.
+#
+# Log failure messages using fail_printf(), with the match file name,
+# and context $7, which is required.
+check_verify_config()
+{
+ if check_empty_pattern "$6" "$7"; then
+ return
+ fi
+
+ FULL_TOR_CMD=
+ verify_config "$1" \
+ "$2" \
+ "$3" \
+ "$4" \
+ "$5" \
+ "$6" \
+ "$7"
+
+ check_pattern "$6" \
+ "$4" \
+ "$7" \
+ "$FULL_TOR_CMD"
+}
+
+for dir in "${EXAMPLEDIR}"/*; do
+ NEXT_TEST=
+
+ if ! test -d "$dir"; then
+ # Only count directories.
+ continue
+ fi
+
+ testname="$(basename "${dir}")"
+ # We use printf since "echo -n" is not standard
+ printf "%s: " \
+ "$testname"
+
+ PREV_DIR="$(pwd)"
+ cd "$dir"
+
+ if test -f "./torrc.defaults"; then
+ DEFAULTS="./torrc.defaults"
+ else
+ DEFAULTS="${DATA_DIR}/EMPTY"
+ fi
+
+ if test -f "./cmdline"; then
+ CMDLINE="$(cat ./cmdline)"
+ else
+ CMDLINE=""
+ fi
+
+ EXPECTED=
+ EXPECTED_LOG=
+ ERROR=
+ # Search for a custom result file for any combination of enabled optional
+ # libraries
+ # The libs in the list are [A-Za-z0-9_]* and space-separated.
+ # shellcheck disable=SC2086
+ for lib_suffix in $TOR_LIBS_ENABLED_SEARCH ""; do
+ # Search for a custom result file for any disabled modules
+ for mod_suffix in "_no_${TOR_MODULES_DISABLED}" ""; do
+ suffix="${lib_suffix}${mod_suffix}"
+
+ if test -f "./expected${suffix}"; then
+
+ # Check for broken configs
+ if test -f "./error${suffix}"; then
+ fail_printf "Found both '%s' and '%s'.%s\\n" \
+ "${dir}/expected${suffix}" \
+ "${dir}/error${suffix}" \
+ "(Only one of these files should exist.)"
+ break
+ fi
+
+ EXPECTED="./expected${suffix}"
+ if test -f "./expected_log${suffix}"; then
+ EXPECTED_LOG="./expected_log${suffix}"
+ fi
+ break
+
+ elif test -f "./error${suffix}"; then
+ ERROR="./error${suffix}"
+ break
+ fi
+ done
+
+ # Exit as soon as the inner loop finds a file, or fails
+ if test -f "$EXPECTED" || test -f "$ERROR" || test "$NEXT_TEST"; then
+ break
+ fi
+ done
+
+ if test "$NEXT_TEST"; then
+ # The test failed inside the file search loop: go to the next test
+ continue
+ elif test -f "$EXPECTED"; then
+ # This case should succeed: run dump-config and see if it does.
+
+ if check_dump_config "./torrc" \
+ "$DEFAULTS" \
+ "$CMDLINE" \
+ "${DATA_DIR}/output.${testname}" \
+ "$EXPECTED" \
+ ""; then
+ # Check round-trip.
+ check_dump_config "${DATA_DIR}/output.${testname}" \
+ "$EMPTY" \
+ "" \
+ "${DATA_DIR}/output_2.${testname}" \
+ "$EXPECTED" \
+ "on round-trip" || true
+ fi
+
+ if test -f "$EXPECTED_LOG"; then
+ # This case should succeed: run verify-config and see if it does.
+
+ check_verify_config "./torrc" \
+ "$DEFAULTS" \
+ "$CMDLINE" \
+ "${DATA_DIR}/output_log.${testname}" \
+ "$TRUE" \
+ "$EXPECTED_LOG" \
+ "log success"
+ else
+ printf "\\nNOTICE: Missing '%s_log' file:\\n" \
+ "$EXPECTED" >&2
+ log_verify_config "./torrc" \
+ "$DEFAULTS" \
+ "$CMDLINE"
+ fi
+
+ elif test -f "$ERROR"; then
+ # This case should fail: run verify-config and see if it does.
+
+ check_verify_config "./torrc" \
+ "$DEFAULTS" \
+ "$CMDLINE" \
+ "${DATA_DIR}/output.${testname}" \
+ "$FALSE" \
+ "$ERROR" \
+ "log error"
+ else
+ # This case is not actually configured with a success or a failure.
+ # call that an error.
+ fail_printf "Did not find ${dir}/*expected or ${dir}/*error.\\n"
+ fi
+
+ if test -z "$NEXT_TEST"; then
+ echo "OK"
+ fi
+
+ cd "$PREV_DIR"
+
+done
+
+exit "$FINAL_EXIT"
diff --git a/src/test/test_pem.c b/src/test/test_pem.c
index 9eb99181e2..9772be124b 100644
--- a/src/test/test_pem.c
+++ b/src/test/test_pem.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_periodic_event.c b/src/test/test_periodic_event.c
index 4a53639dad..d3bc89673b 100644
--- a/src/test/test_periodic_event.c
+++ b/src/test/test_periodic_event.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,8 +17,10 @@
#include "core/or/or.h"
#include "app/config/config.h"
#include "feature/hibernate/hibernate.h"
+#include "feature/hs/hs_metrics.h"
#include "feature/hs/hs_service.h"
#include "core/mainloop/mainloop.h"
+#include "core/mainloop/netstatus.h"
#include "core/mainloop/periodic.h"
/** Helper function: This is replaced in some tests for the event callbacks so
@@ -50,16 +52,21 @@ test_pe_initialize(void *arg)
* need to run the main loop and then wait for a second delaying the unit
* tests. Instead, we'll test the callback work indepedently elsewhere. */
initialize_periodic_events();
+ periodic_events_connect_all();
+ set_network_participation(false);
+ rescan_periodic_events(get_options());
/* Validate that all events have been set up. */
- for (int i = 0; periodic_events[i].name; ++i) {
- periodic_event_item_t *item = &periodic_events[i];
+ for (int i = 0; mainloop_periodic_events[i].name; ++i) {
+ periodic_event_item_t *item = &mainloop_periodic_events[i];
tt_assert(item->ev);
tt_assert(item->fn);
tt_u64_op(item->last_action_time, OP_EQ, 0);
/* Every event must have role(s) assign to it. This is done statically. */
tt_u64_op(item->roles, OP_NE, 0);
- tt_uint_op(periodic_event_is_enabled(item), OP_EQ, 0);
+ int should_be_enabled = (item->roles & PERIODIC_EVENT_ROLE_ALL) &&
+ !(item->flags & PERIODIC_EVENT_FLAG_NEED_NET);
+ tt_uint_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
}
done:
@@ -79,19 +86,22 @@ test_pe_launch(void *arg)
* network gets enabled. */
consider_hibernation(time(NULL));
+ set_network_participation(true);
+
/* Hack: We'll set a dumb fn() of each events so they don't get called when
* dispatching them. We just want to test the state of the callbacks, not
* the whole code path. */
- for (int i = 0; periodic_events[i].name; ++i) {
- periodic_event_item_t *item = &periodic_events[i];
+ for (int i = 0; mainloop_periodic_events[i].name; ++i) {
+ periodic_event_item_t *item = &mainloop_periodic_events[i];
item->fn = dumb_event_fn;
}
options = get_options_mutable();
options->SocksPort_set = 1;
periodic_events_on_new_options(options);
+
#if 0
- /* Lets make sure that before intialization, we can't scan the periodic
+ /* Lets make sure that before initialization, we can't scan the periodic
* events list and launch them. Lets try by being a Client. */
/* XXXX We make sure these events are initialized now way earlier than we
* did before. */
@@ -99,20 +109,20 @@ test_pe_launch(void *arg)
periodic_event_item_t *item = &periodic_events[i];
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
}
-#endif
+#endif /* 0 */
initialize_periodic_events();
+ periodic_events_connect_all();
/* Now that we've initialized, rescan the list to launch. */
periodic_events_on_new_options(options);
- for (int i = 0; periodic_events[i].name; ++i) {
- periodic_event_item_t *item = &periodic_events[i];
- if (item->roles & PERIODIC_EVENT_ROLE_CLIENT) {
- tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
- } else {
- tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
- }
+ int mask = PERIODIC_EVENT_ROLE_CLIENT|PERIODIC_EVENT_ROLE_ALL|
+ PERIODIC_EVENT_ROLE_NET_PARTICIPANT;
+ for (int i = 0; mainloop_periodic_events[i].name; ++i) {
+ periodic_event_item_t *item = &mainloop_periodic_events[i];
+ int should_be_enabled = !!(item->roles & mask);
+ tt_int_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
// enabled or not, the event has not yet been run.
tt_u64_op(item->last_action_time, OP_EQ, 0);
}
@@ -124,10 +134,11 @@ test_pe_launch(void *arg)
unsigned roles = get_my_roles(options);
tt_uint_op(roles, OP_EQ,
- PERIODIC_EVENT_ROLE_RELAY|PERIODIC_EVENT_ROLE_DIRSERVER);
+ PERIODIC_EVENT_ROLE_RELAY|PERIODIC_EVENT_ROLE_DIRSERVER|
+ PERIODIC_EVENT_ROLE_ALL|PERIODIC_EVENT_ROLE_NET_PARTICIPANT);
- for (int i = 0; periodic_events[i].name; ++i) {
- periodic_event_item_t *item = &periodic_events[i];
+ for (int i = 0; mainloop_periodic_events[i].name; ++i) {
+ periodic_event_item_t *item = &mainloop_periodic_events[i];
/* Only Client role should be disabled. */
if (item->roles == PERIODIC_EVENT_ROLE_CLIENT) {
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
@@ -144,17 +155,23 @@ test_pe_launch(void *arg)
/* Disable everything and we'll enable them ALL. */
options->SocksPort_set = 0;
options->ORPort_set = 0;
+ options->DisableNetwork = 1;
+ set_network_participation(false);
periodic_events_on_new_options(options);
- for (int i = 0; periodic_events[i].name; ++i) {
- periodic_event_item_t *item = &periodic_events[i];
- tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
+ for (int i = 0; mainloop_periodic_events[i].name; ++i) {
+ periodic_event_item_t *item = &mainloop_periodic_events[i];
+ int should_be_enabled = (item->roles & PERIODIC_EVENT_ROLE_ALL) &&
+ !(item->flags & PERIODIC_EVENT_FLAG_NEED_NET);
+ tt_int_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
}
/* Enable everything. */
options->SocksPort_set = 1; options->ORPort_set = 1;
options->BridgeRelay = 1; options->AuthoritativeDir = 1;
options->V3AuthoritativeDir = 1; options->BridgeAuthoritativeDir = 1;
+ options->DisableNetwork = 0;
+ set_network_participation(true);
register_dummy_hidden_service(&service);
periodic_events_on_new_options(options);
/* Note down the reference because we need to remove this service from the
@@ -163,13 +180,15 @@ test_pe_launch(void *arg)
* trigger a rescan of the event disabling the HS service event. */
to_remove = &service;
- for (int i = 0; periodic_events[i].name; ++i) {
- periodic_event_item_t *item = &periodic_events[i];
- tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
+ for (int i = 0; mainloop_periodic_events[i].name; ++i) {
+ periodic_event_item_t *item = &mainloop_periodic_events[i];
+ tt_int_op(periodic_event_is_enabled(item), OP_EQ,
+ (item->roles != PERIODIC_EVENT_ROLE_CONTROLEV));
}
done:
if (to_remove) {
+ hs_metrics_service_free(&service);
remove_service(get_hs_service_map(), to_remove);
}
hs_free_all();
@@ -187,42 +206,49 @@ test_pe_get_roles(void *arg)
or_options_t *options = get_options_mutable();
tt_assert(options);
+ set_network_participation(true);
+
+ const int ALL = PERIODIC_EVENT_ROLE_ALL |
+ PERIODIC_EVENT_ROLE_NET_PARTICIPANT;
/* Nothing configured, should be no roles. */
+ tt_assert(net_is_disabled());
roles = get_my_roles(options);
- tt_int_op(roles, OP_EQ, 0);
+ tt_int_op(roles, OP_EQ, ALL);
/* Indicate we have a SocksPort, roles should be come Client. */
options->SocksPort_set = 1;
roles = get_my_roles(options);
- tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_CLIENT);
+ tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_CLIENT|ALL);
/* Now, we'll add a ORPort so should now be a Relay + Client. */
options->ORPort_set = 1;
roles = get_my_roles(options);
tt_int_op(roles, OP_EQ,
(PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
- PERIODIC_EVENT_ROLE_DIRSERVER));
+ PERIODIC_EVENT_ROLE_DIRSERVER | ALL));
/* Now add a Bridge. */
options->BridgeRelay = 1;
roles = get_my_roles(options);
tt_int_op(roles, OP_EQ,
(PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
- PERIODIC_EVENT_ROLE_BRIDGE | PERIODIC_EVENT_ROLE_DIRSERVER));
+ PERIODIC_EVENT_ROLE_BRIDGE | PERIODIC_EVENT_ROLE_DIRSERVER |
+ ALL));
tt_assert(roles & PERIODIC_EVENT_ROLE_ROUTER);
/* Unset client so we can solely test Router role. */
options->SocksPort_set = 0;
roles = get_my_roles(options);
tt_int_op(roles, OP_EQ,
- PERIODIC_EVENT_ROLE_ROUTER | PERIODIC_EVENT_ROLE_DIRSERVER);
+ PERIODIC_EVENT_ROLE_ROUTER | PERIODIC_EVENT_ROLE_DIRSERVER |
+ ALL);
/* Reset options so we can test authorities. */
options->SocksPort_set = 0;
options->ORPort_set = 0;
options->BridgeRelay = 0;
roles = get_my_roles(options);
- tt_int_op(roles, OP_EQ, 0);
+ tt_int_op(roles, OP_EQ, ALL);
/* Now upgrade to Dirauth. */
options->DirPort_set = 1;
@@ -230,7 +256,7 @@ test_pe_get_roles(void *arg)
options->V3AuthoritativeDir = 1;
roles = get_my_roles(options);
tt_int_op(roles, OP_EQ,
- PERIODIC_EVENT_ROLE_DIRAUTH|PERIODIC_EVENT_ROLE_DIRSERVER);
+ PERIODIC_EVENT_ROLE_DIRAUTH|PERIODIC_EVENT_ROLE_DIRSERVER|ALL);
tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
/* Now Bridge Authority. */
@@ -238,7 +264,7 @@ test_pe_get_roles(void *arg)
options->BridgeAuthoritativeDir = 1;
roles = get_my_roles(options);
tt_int_op(roles, OP_EQ,
- PERIODIC_EVENT_ROLE_BRIDGEAUTH|PERIODIC_EVENT_ROLE_DIRSERVER);
+ PERIODIC_EVENT_ROLE_BRIDGEAUTH|PERIODIC_EVENT_ROLE_DIRSERVER|ALL);
tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
/* Move that bridge auth to become a relay. */
@@ -246,7 +272,7 @@ test_pe_get_roles(void *arg)
roles = get_my_roles(options);
tt_int_op(roles, OP_EQ,
(PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY
- | PERIODIC_EVENT_ROLE_DIRSERVER));
+ | PERIODIC_EVENT_ROLE_DIRSERVER|ALL));
tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
/* And now an Hidden service. */
@@ -255,9 +281,11 @@ test_pe_get_roles(void *arg)
roles = get_my_roles(options);
/* Remove it now so the hs_free_all() doesn't try to free stack memory. */
remove_service(get_hs_service_map(), &service);
+ hs_metrics_service_free(&service);
tt_int_op(roles, OP_EQ,
(PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY |
- PERIODIC_EVENT_ROLE_HS_SERVICE | PERIODIC_EVENT_ROLE_DIRSERVER));
+ PERIODIC_EVENT_ROLE_HS_SERVICE | PERIODIC_EVENT_ROLE_DIRSERVER |
+ ALL));
tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
done:
@@ -277,12 +305,13 @@ test_pe_hs_service(void *arg)
consider_hibernation(time(NULL));
/* Initialize the events so we can enable them */
initialize_periodic_events();
+ periodic_events_connect_all();
/* Hack: We'll set a dumb fn() of each events so they don't get called when
* dispatching them. We just want to test the state of the callbacks, not
* the whole code path. */
- for (int i = 0; periodic_events[i].name; ++i) {
- periodic_event_item_t *item = &periodic_events[i];
+ for (int i = 0; mainloop_periodic_events[i].name; ++i) {
+ periodic_event_item_t *item = &mainloop_periodic_events[i];
item->fn = dumb_event_fn;
}
@@ -295,8 +324,8 @@ test_pe_hs_service(void *arg)
* trigger a rescan of the event disabling the HS service event. */
to_remove = &service;
- for (int i = 0; periodic_events[i].name; ++i) {
- periodic_event_item_t *item = &periodic_events[i];
+ for (int i = 0; mainloop_periodic_events[i].name; ++i) {
+ periodic_event_item_t *item = &mainloop_periodic_events[i];
if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) {
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
}
@@ -306,8 +335,9 @@ test_pe_hs_service(void *arg)
/* Remove the service from the global map, it should trigger a rescan and
* disable the HS service events. */
remove_service(get_hs_service_map(), &service);
- for (int i = 0; periodic_events[i].name; ++i) {
- periodic_event_item_t *item = &periodic_events[i];
+ hs_metrics_service_free(&service);
+ for (int i = 0; mainloop_periodic_events[i].name; ++i) {
+ periodic_event_item_t *item = &mainloop_periodic_events[i];
if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) {
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
}
@@ -315,6 +345,7 @@ test_pe_hs_service(void *arg)
done:
if (to_remove) {
+ hs_metrics_service_free(&service);
remove_service(get_hs_service_map(), to_remove);
}
hs_free_all();
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 9c001c294a..0a0548d161 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2019, The Tor Project, Inc. */
+/* Copyright (c) 2013-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
@@ -6,13 +6,19 @@
#include "core/or/or.h"
#include "app/config/config.h"
+#include "core/or/circuitbuild.h"
#include "core/or/policies.h"
+#include "core/or/extendinfo.h"
#include "feature/dirparse/policy_parse.h"
+#include "feature/hs/hs_common.h"
+#include "feature/hs/hs_descriptor.h"
#include "feature/relay/router.h"
#include "lib/encoding/confline.h"
#include "test/test.h"
+#include "test/log_test_helpers.h"
#include "core/or/addr_policy_st.h"
+#include "core/or/extend_info_st.h"
#include "core/or/port_cfg_st.h"
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
@@ -57,8 +63,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,
@@ -1119,7 +1125,7 @@ test_policy_has_address_helper(const smartlist_t *policy_list,
return 0;
}
-#define TEST_IPV4_ADDR (0x01020304)
+#define TEST_IPV4_ADDR ("1.2.3.4")
#define TEST_IPV6_ADDR ("2002::abcd")
/** Run unit tests for rejecting the configured addresses on this exit relay
@@ -1132,7 +1138,7 @@ test_policies_reject_exit_address(void *arg)
smartlist_t *ipv4_list, *ipv6_list, *both_list, *dupl_list;
(void)arg;
- tor_addr_from_ipv4h(&ipv4_addr, TEST_IPV4_ADDR);
+ tor_addr_parse(&ipv4_addr, TEST_IPV4_ADDR);
tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR);
ipv4_list = smartlist_new();
@@ -1250,7 +1256,7 @@ test_policies_reject_port_address(void *arg)
test_configured_ports = smartlist_new();
ipv4_port = port_cfg_new(0);
- tor_addr_from_ipv4h(&ipv4_port->addr, TEST_IPV4_ADDR);
+ tor_addr_parse(&ipv4_port->addr, TEST_IPV4_ADDR);
smartlist_add(test_configured_ports, ipv4_port);
ipv6_port = port_cfg_new(0);
@@ -1368,7 +1374,7 @@ test_policies_reject_interface_address(void *arg)
}
/* Now do it all again, but mocked */
- tor_addr_from_ipv4h(&ipv4_addr, TEST_IPV4_ADDR);
+ tor_addr_parse(&ipv4_addr, TEST_IPV4_ADDR);
mock_ipv4_addrs = smartlist_new();
smartlist_add(mock_ipv4_addrs, (void *)&ipv4_addr);
@@ -1523,7 +1529,7 @@ mock_router_get_my_routerinfo_with_err(int *err)
}
#define DEFAULT_POLICY_STRING "reject *:*"
-#define TEST_IPV4_ADDR (0x02040608)
+#define TEST_IPV4_ADDR ("2.4.6.8")
#define TEST_IPV6_ADDR ("2003::ef01")
static or_options_t mock_options;
@@ -1602,13 +1608,13 @@ test_policies_getinfo_helper_policies(void *arg)
tt_assert(strlen(answer) == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING));
tor_free(answer);
- mock_my_routerinfo.addr = TEST_IPV4_ADDR;
+ tor_addr_parse(&mock_my_routerinfo.ipv4_addr, TEST_IPV4_ADDR);
tor_addr_parse(&mock_my_routerinfo.ipv6_addr, TEST_IPV6_ADDR);
append_exit_policy_string(&mock_my_routerinfo.exit_policy, "accept *4:*");
append_exit_policy_string(&mock_my_routerinfo.exit_policy, "reject *6:*");
mock_options.IPv6Exit = 1;
- tor_addr_from_ipv4h(
+ tor_addr_parse(
&mock_options.OutboundBindAddresses[OUTBOUND_ADDR_EXIT][0],
TEST_IPV4_ADDR);
tor_addr_parse(
@@ -1747,7 +1753,7 @@ test_policies_getinfo_helper_policies(void *arg)
#define OTHER_IPV4_ADDR_STR "6.7.8.9"
#define OTHER_IPV6_ADDR_STR "[afff::]"
-/** Run unit tests for fascist_firewall_allows_address */
+/** Run unit tests for reachable_addr_allows */
static void
test_policies_fascist_firewall_allows_address(void *arg)
{
@@ -1816,33 +1822,33 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 0;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Preferring IPv4 */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 0),
OP_EQ, 0);
/* Preferring IPv6 */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 1),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 1),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 1),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 1),
OP_EQ, 0);
/* Test the function's address matching with UseBridges on */
@@ -1851,45 +1857,45 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 1;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Preferring IPv4 */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 0),
OP_EQ, 0);
/* Preferring IPv6 */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 1),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 1),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 1),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 1),
OP_EQ, 0);
/* bridge clients always use IPv6, regardless of ClientUseIPv6 */
mock_options.ClientUseIPv4 = 1;
mock_options.ClientUseIPv6 = 0;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Test the function's address matching with IPv4 on */
@@ -1898,13 +1904,13 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 0;
mock_options.UseBridges = 0;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Test the function's address matching with IPv6 on */
@@ -1913,13 +1919,13 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 0;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Test the function's address matching with ClientUseIPv4 0.
@@ -1929,13 +1935,13 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 0;
mock_options.UseBridges = 0;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Test the function's address matching for unusual inputs */
@@ -1945,27 +1951,27 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.UseBridges = 1;
/* NULL and tor_addr_is_null addresses are rejected */
- tt_int_op(fascist_firewall_allows_address(NULL, port, policy, 0, 0), OP_EQ,
+ tt_int_op(reachable_addr_allows(NULL, port, policy, 0, 0), OP_EQ,
0);
- tt_int_op(fascist_firewall_allows_address(&n_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&n_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&n_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&n_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* zero ports are rejected */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, 0, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, 0, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, 0, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, 0, policy, 0, 0),
OP_EQ, 0);
/* NULL and empty policies accept everything */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, NULL, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, NULL, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, NULL, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, NULL, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, e_policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, e_policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, e_policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, e_policy, 0, 0),
OP_EQ, 1);
done:
@@ -1985,7 +1991,7 @@ test_policies_fascist_firewall_allows_address(void *arg)
#define TEST_IPV6_OR_PORT 61234
#define TEST_IPV6_DIR_PORT 62345
-/* Check that fascist_firewall_choose_address_rs() returns the expected
+/* Check that reachable_addr_choose_from_rs() returns the expected
* results. */
#define CHECK_CHOSEN_ADDR_RS(fake_rs, fw_connection, pref_only, expect_rv, \
expect_ap) \
@@ -1993,13 +1999,13 @@ test_policies_fascist_firewall_allows_address(void *arg)
tor_addr_port_t chosen_rs_ap; \
tor_addr_make_null(&chosen_rs_ap.addr, AF_INET); \
chosen_rs_ap.port = 0; \
- fascist_firewall_choose_address_rs(&(fake_rs), (fw_connection), \
+ reachable_addr_choose_from_rs(&(fake_rs), (fw_connection), \
(pref_only), &chosen_rs_ap); \
tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_rs_ap.addr)); \
tt_int_op((expect_ap).port, OP_EQ, chosen_rs_ap.port); \
STMT_END
-/* Check that fascist_firewall_choose_address_node() returns the expected
+/* Check that reachable_addr_choose_from_node() returns the expected
* results. */
#define CHECK_CHOSEN_ADDR_NODE(fake_node, fw_connection, pref_only, \
expect_rv, expect_ap) \
@@ -2007,14 +2013,14 @@ test_policies_fascist_firewall_allows_address(void *arg)
tor_addr_port_t chosen_node_ap; \
tor_addr_make_null(&chosen_node_ap.addr, AF_INET); \
chosen_node_ap.port = 0; \
- fascist_firewall_choose_address_node(&(fake_node),(fw_connection), \
+ reachable_addr_choose_from_node(&(fake_node),(fw_connection), \
(pref_only), &chosen_node_ap); \
tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_node_ap.addr)); \
tt_int_op((expect_ap).port, OP_EQ, chosen_node_ap.port); \
STMT_END
-/* Check that fascist_firewall_choose_address_rs and
- * fascist_firewall_choose_address_node() both return the expected results. */
+/* Check that reachable_addr_choose_from_rs and
+ * reachable_addr_choose_from_node() both return the expected results. */
#define CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, fw_connection, pref_only, \
expect_rv, expect_ap) \
STMT_BEGIN \
@@ -2024,7 +2030,102 @@ test_policies_fascist_firewall_allows_address(void *arg)
expect_ap); \
STMT_END
-/** Run unit tests for fascist_firewall_choose_address */
+/* Check that reachable_addr_choose_from_ls() returns the expected
+ * results. */
+#define CHECK_CHOSEN_ADDR_NULL_LS() \
+ STMT_BEGIN \
+ tor_addr_port_t chosen_ls_ap; \
+ tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \
+ chosen_ls_ap.port = 0; \
+ setup_full_capture_of_logs(LOG_WARN); \
+ reachable_addr_choose_from_ls(NULL, 1, &chosen_ls_ap); \
+ expect_single_log_msg("Unknown or missing link specifiers"); \
+ teardown_capture_of_logs(); \
+ STMT_END
+
+#define CHECK_CHOSEN_ADDR_LS(fake_ls, pref_only, expect_rv, expect_ap) \
+ STMT_BEGIN \
+ tor_addr_port_t chosen_ls_ap; \
+ tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \
+ chosen_ls_ap.port = 0; \
+ setup_full_capture_of_logs(LOG_WARN); \
+ reachable_addr_choose_from_ls(fake_ls, pref_only, &chosen_ls_ap); \
+ if (smartlist_len(fake_ls) == 0) { \
+ expect_single_log_msg("Link specifiers are empty"); \
+ } else { \
+ expect_no_log_entry(); \
+ tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_ls_ap.addr)); \
+ tt_int_op((expect_ap).port, OP_EQ, chosen_ls_ap.port); \
+ } \
+ teardown_capture_of_logs(); \
+ STMT_END
+
+#define CHECK_LS_LEGACY_ONLY(fake_ls) \
+ STMT_BEGIN \
+ tor_addr_port_t chosen_ls_ap; \
+ tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \
+ chosen_ls_ap.port = 0; \
+ setup_full_capture_of_logs(LOG_WARN); \
+ reachable_addr_choose_from_ls(fake_ls, 0, &chosen_ls_ap); \
+ expect_single_log_msg("None of our link specifiers have IPv4 or IPv6"); \
+ teardown_capture_of_logs(); \
+ STMT_END
+
+#define CHECK_HS_EXTEND_INFO_ADDR_LS(fake_ls, direct_conn, expect_ap) \
+ STMT_BEGIN \
+ curve25519_secret_key_t seckey; \
+ curve25519_secret_key_generate(&seckey, 0); \
+ curve25519_public_key_t pubkey; \
+ curve25519_public_key_generate(&pubkey, &seckey); \
+ setup_full_capture_of_logs(LOG_WARN); \
+ extend_info_t *ei = hs_get_extend_info_from_lspecs(fake_ls, &pubkey, \
+ direct_conn); \
+ if (fake_ls == NULL) { \
+ tt_ptr_op(ei, OP_EQ, NULL); \
+ expect_single_log_msg("Specified link specifiers is null"); \
+ } else { \
+ expect_no_log_entry(); \
+ tt_assert(tor_addr_eq(&(expect_ap).addr, &ei->orports[0].addr)); \
+ tt_int_op((expect_ap).port, OP_EQ, ei->orports[0].port); \
+ extend_info_free(ei); \
+ } \
+ teardown_capture_of_logs(); \
+ STMT_END
+
+#define CHECK_HS_EXTEND_INFO_ADDR_LS_NULL_KEY(fake_ls) \
+ STMT_BEGIN \
+ setup_full_capture_of_logs(LOG_WARN); \
+ extend_info_t *ei = hs_get_extend_info_from_lspecs(fake_ls, NULL, 0); \
+ tt_ptr_op(ei, OP_EQ, NULL); \
+ expect_single_log_msg("Specified onion key is null"); \
+ teardown_capture_of_logs(); \
+ STMT_END
+
+#define CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(fake_ls, direct_conn) \
+ STMT_BEGIN \
+ curve25519_secret_key_t seckey; \
+ curve25519_secret_key_generate(&seckey, 0); \
+ curve25519_public_key_t pubkey; \
+ curve25519_public_key_generate(&pubkey, &seckey); \
+ extend_info_t *ei = hs_get_extend_info_from_lspecs(fake_ls, &pubkey, \
+ direct_conn); \
+ tt_ptr_op(ei, OP_EQ, NULL); \
+ STMT_END
+
+#define CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_MSG(fake_ls, msg_level, msg) \
+ STMT_BEGIN \
+ curve25519_secret_key_t seckey; \
+ curve25519_secret_key_generate(&seckey, 0); \
+ curve25519_public_key_t pubkey; \
+ curve25519_public_key_generate(&pubkey, &seckey); \
+ setup_full_capture_of_logs(msg_level); \
+ extend_info_t *ei = hs_get_extend_info_from_lspecs(fake_ls, &pubkey, 0); \
+ tt_ptr_op(ei, OP_EQ, NULL); \
+ expect_single_log_msg(msg); \
+ teardown_capture_of_logs(); \
+ STMT_END
+
+/** Run unit tests for reachable_addr_choose */
static void
test_policies_fascist_firewall_choose_address(void *arg)
{
@@ -2052,87 +2153,87 @@ test_policies_fascist_firewall_choose_address(void *arg)
tor_addr_make_null(&n_ipv6_ap.addr, AF_INET6);
n_ipv6_ap.port = 0;
- /* Sanity check fascist_firewall_choose_address with IPv4 and IPv6 on */
+ /* Sanity check reachable_addr_choose with IPv4 and IPv6 on */
memset(&mock_options, 0, sizeof(or_options_t));
mock_options.ClientUseIPv4 = 1;
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 0;
/* Prefer IPv4 */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1,
FIREWALL_OR_CONNECTION, 0, 0)
== &ipv4_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1,
FIREWALL_OR_CONNECTION, 1, 0)
== &ipv4_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 1,
FIREWALL_DIR_CONNECTION, 0, 0)
== &ipv4_dir_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 1,
FIREWALL_DIR_CONNECTION, 1, 0)
== &ipv4_dir_ap);
/* Prefer IPv6 */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0,
FIREWALL_OR_CONNECTION, 0, 1)
== &ipv6_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0,
FIREWALL_OR_CONNECTION, 1, 1)
== &ipv6_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 0,
FIREWALL_DIR_CONNECTION, 0, 1)
== &ipv6_dir_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 0,
FIREWALL_DIR_CONNECTION, 1, 1)
== &ipv6_dir_ap);
/* Unusual inputs */
/* null preferred OR addresses */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &n_ipv6_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &n_ipv6_ap, 0,
FIREWALL_OR_CONNECTION, 0, 1)
== &ipv4_or_ap);
- tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_or_ap, 1,
+ tt_assert(reachable_addr_choose(&n_ipv4_ap, &ipv6_or_ap, 1,
FIREWALL_OR_CONNECTION, 0, 0)
== &ipv6_or_ap);
/* null both OR addresses */
- tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
+ tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 0,
FIREWALL_OR_CONNECTION, 0, 1),
OP_EQ, NULL);
- tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1,
+ tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 1,
FIREWALL_OR_CONNECTION, 0, 0),
OP_EQ, NULL);
/* null preferred Dir addresses */
- tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &n_ipv6_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_dir_ap, &n_ipv6_ap, 0,
FIREWALL_DIR_CONNECTION, 0, 1)
== &ipv4_dir_ap);
- tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_dir_ap, 1,
+ tt_assert(reachable_addr_choose(&n_ipv4_ap, &ipv6_dir_ap, 1,
FIREWALL_DIR_CONNECTION, 0, 0)
== &ipv6_dir_ap);
/* null both Dir addresses */
- tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
+ tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 0,
FIREWALL_DIR_CONNECTION, 0, 1),
OP_EQ, NULL);
- tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1,
+ tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 1,
FIREWALL_DIR_CONNECTION, 0, 0),
OP_EQ, NULL);
/* Prefer IPv4 but want IPv6 (contradictory) */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0,
FIREWALL_OR_CONNECTION, 0, 0)
== &ipv4_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0,
FIREWALL_OR_CONNECTION, 1, 0)
== &ipv4_or_ap);
/* Prefer IPv6 but want IPv4 (contradictory) */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1,
FIREWALL_OR_CONNECTION, 0, 1)
== &ipv6_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1,
FIREWALL_OR_CONNECTION, 1, 1)
== &ipv6_or_ap);
@@ -2142,9 +2243,9 @@ test_policies_fascist_firewall_choose_address(void *arg)
routerstatus_t fake_rs;
memset(&fake_rs, 0, sizeof(routerstatus_t));
/* In a routerstatus, the OR and Dir addresses are the same */
- fake_rs.addr = tor_addr_to_ipv4h(&ipv4_or_ap.addr);
- fake_rs.or_port = ipv4_or_ap.port;
- fake_rs.dir_port = ipv4_dir_ap.port;
+ tor_addr_copy(&fake_rs.ipv4_addr, &ipv4_or_ap.addr);
+ fake_rs.ipv4_orport = ipv4_or_ap.port;
+ fake_rs.ipv4_dirport = ipv4_dir_ap.port;
tor_addr_copy(&fake_rs.ipv6_addr, &ipv6_or_ap.addr);
fake_rs.ipv6_orport = ipv6_or_ap.port;
@@ -2167,7 +2268,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 0;
mock_options.ClientPreferIPv6DirPort = 0;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2183,7 +2284,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = -1;
mock_options.ClientPreferIPv6DirPort = -1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2199,7 +2300,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 1;
mock_options.ClientPreferIPv6DirPort = 1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2215,7 +2316,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 0;
mock_options.ClientPreferIPv6DirPort = 1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2231,7 +2332,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 1;
mock_options.ClientPreferIPv6DirPort = 0;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2253,7 +2354,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 0;
mock_options.ClientPreferIPv6DirPort = 0;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2304,7 +2405,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 1;
mock_options.ClientPreferIPv6DirPort = 1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2353,7 +2454,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientUseIPv4 = 1;
mock_options.ClientUseIPv6 = 0;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2370,7 +2471,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientUseIPv4 = 0;
mock_options.ClientUseIPv6 = 1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2388,7 +2489,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientUseIPv4 = 0;
mock_options.ClientUseIPv6 = 0;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2410,7 +2511,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6DirPort = 1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2422,6 +2523,141 @@ 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 firewall_choose_address_ls(). To do this, we make a fake link
+ * specifier. */
+ smartlist_t *lspecs = smartlist_new(),
+ *lspecs_blank = smartlist_new(),
+ *lspecs_v4 = smartlist_new(),
+ *lspecs_v6 = smartlist_new(),
+ *lspecs_no_legacy = smartlist_new(),
+ *lspecs_legacy_only = smartlist_new();
+ link_specifier_t *fake_ls;
+
+ /* IPv4 link specifier */
+ fake_ls = link_specifier_new();
+ link_specifier_set_ls_type(fake_ls, LS_IPV4);
+ link_specifier_set_un_ipv4_addr(fake_ls,
+ tor_addr_to_ipv4h(&ipv4_or_ap.addr));
+ link_specifier_set_un_ipv4_port(fake_ls, ipv4_or_ap.port);
+ link_specifier_set_ls_len(fake_ls, sizeof(ipv4_or_ap.addr.addr.in_addr) +
+ sizeof(ipv4_or_ap.port));
+ smartlist_add(lspecs, fake_ls);
+ smartlist_add(lspecs_v4, fake_ls);
+ smartlist_add(lspecs_no_legacy, fake_ls);
+
+ /* IPv6 link specifier */
+ fake_ls = link_specifier_new();
+ link_specifier_set_ls_type(fake_ls, LS_IPV6);
+ size_t addr_len = link_specifier_getlen_un_ipv6_addr(fake_ls);
+ const uint8_t *in6_addr = tor_addr_to_in6_addr8(&ipv6_or_ap.addr);
+ uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(fake_ls);
+ memcpy(ipv6_array, in6_addr, addr_len);
+ link_specifier_set_un_ipv6_port(fake_ls, ipv6_or_ap.port);
+ link_specifier_set_ls_len(fake_ls, addr_len + sizeof(ipv6_or_ap.port));
+ smartlist_add(lspecs, fake_ls);
+ smartlist_add(lspecs_v6, fake_ls);
+
+ /* Legacy ID link specifier */
+ fake_ls = link_specifier_new();
+ link_specifier_set_ls_type(fake_ls, LS_LEGACY_ID);
+ uint8_t *legacy_id = link_specifier_getarray_un_legacy_id(fake_ls);
+ memset(legacy_id, 'A', sizeof(*legacy_id));
+ link_specifier_set_ls_len(fake_ls,
+ link_specifier_getlen_un_legacy_id(fake_ls));
+ smartlist_add(lspecs, fake_ls);
+ smartlist_add(lspecs_legacy_only, fake_ls);
+ smartlist_add(lspecs_v4, fake_ls);
+ smartlist_add(lspecs_v6, fake_ls);
+
+ /* Check with bogus requests. */
+ tor_addr_port_t null_ap; \
+ tor_addr_make_null(&null_ap.addr, AF_UNSPEC); \
+ null_ap.port = 0; \
+
+ /* Check for a null link state. */
+ CHECK_CHOSEN_ADDR_NULL_LS();
+ CHECK_HS_EXTEND_INFO_ADDR_LS(NULL, 1, null_ap);
+
+ /* Check for a blank link state. */
+ CHECK_CHOSEN_ADDR_LS(lspecs_blank, 0, 0, null_ap);
+ CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_blank, 0);
+
+ /* Check for a link state with only a Legacy ID. */
+ CHECK_LS_LEGACY_ONLY(lspecs_legacy_only);
+ CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_legacy_only, 0);
+ smartlist_free(lspecs_legacy_only);
+
+ /* Check with a null onion_key. */
+ CHECK_HS_EXTEND_INFO_ADDR_LS_NULL_KEY(lspecs_blank);
+ smartlist_free(lspecs_blank);
+
+ /* Check with a null onion_key. */
+ CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_MSG(lspecs_no_legacy, LOG_WARN,
+ "Missing Legacy ID in link state");
+ smartlist_free(lspecs_no_legacy);
+
+ /* Enable both IPv4 and IPv6. */
+ memset(&mock_options, 0, sizeof(or_options_t));
+ mock_options.ClientUseIPv4 = 1;
+ mock_options.ClientUseIPv6 = 1;
+
+ /* Prefer IPv4, enable both IPv4 and IPv6. */
+ mock_options.ClientPreferIPv6ORPort = 0;
+
+ CHECK_CHOSEN_ADDR_LS(lspecs, 0, 1, ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_LS(lspecs, 1, 1, ipv4_or_ap);
+
+ CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 1, ipv4_or_ap);
+ CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 0, ipv4_or_ap);
+
+ /* Prefer IPv6, enable both IPv4 and IPv6. */
+ mock_options.ClientPreferIPv6ORPort = 1;
+
+ CHECK_CHOSEN_ADDR_LS(lspecs, 0, 1, ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_LS(lspecs, 1, 1, ipv6_or_ap);
+
+ CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 1, ipv6_or_ap);
+ CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 0, ipv4_or_ap);
+
+ /* IPv4-only. */
+ memset(&mock_options, 0, sizeof(or_options_t));
+ mock_options.ClientUseIPv4 = 1;
+ mock_options.ClientUseIPv6 = 0;
+
+ CHECK_CHOSEN_ADDR_LS(lspecs, 0, 1, ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_LS(lspecs, 1, 1, ipv4_or_ap);
+
+ CHECK_CHOSEN_ADDR_LS(lspecs_v6, 0, 0, null_ap);
+
+ CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 1, ipv4_or_ap);
+ CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 0, ipv4_or_ap);
+
+ CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_v6, 0);
+ CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_v6, 1);
+
+ /* IPv6-only. */
+ memset(&mock_options, 0, sizeof(or_options_t));
+ mock_options.ClientUseIPv4 = 0;
+ mock_options.ClientUseIPv6 = 1;
+
+ CHECK_CHOSEN_ADDR_LS(lspecs, 0, 1, ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_LS(lspecs, 1, 1, ipv6_or_ap);
+
+ CHECK_CHOSEN_ADDR_LS(lspecs_v4, 0, 0, null_ap);
+
+ CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 1, ipv6_or_ap);
+ CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 0, ipv4_or_ap);
+
+ CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_v4, 1);
+ CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_v6, 0);
+
+ smartlist_free(lspecs_v4);
+ smartlist_free(lspecs_v6);
+
+ SMARTLIST_FOREACH(lspecs, link_specifier_t *, lspec, \
+ link_specifier_free(lspec)); \
+ smartlist_free(lspecs);
+
done:
UNMOCK(get_options);
}
@@ -2447,9 +2683,9 @@ struct testcase_t policy_tests[] = {
{ "reject_interface_address", test_policies_reject_interface_address, 0,
NULL, NULL },
{ "reject_port_address", test_policies_reject_port_address, 0, NULL, NULL },
- { "fascist_firewall_allows_address",
+ { "reachable_addr_allows",
test_policies_fascist_firewall_allows_address, 0, NULL, NULL },
- { "fascist_firewall_choose_address",
+ { "reachable_addr_choose",
test_policies_fascist_firewall_choose_address, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_prob_distr.c b/src/test/test_prob_distr.c
new file mode 100644
index 0000000000..da65a0f26d
--- /dev/null
+++ b/src/test/test_prob_distr.c
@@ -0,0 +1,1406 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_prob_distr.c
+ * \brief Test probability distributions.
+ * \detail
+ *
+ * For each probability distribution we do two kinds of tests:
+ *
+ * a) We do numerical deterministic testing of their cdf/icdf/sf/isf functions
+ * and the various relationships between them for each distribution. We also
+ * do deterministic tests on their sampling functions. Test vectors for
+ * these tests were computed from alternative implementations and were
+ * eyeballed to make sure they make sense
+ * (e.g. src/test/prob_distr_mpfr_ref.c computes logit(p) using GNU mpfr
+ * with 200-bit precision and is then tested in test_logit_logistic()).
+ *
+ * b) We do stochastic hypothesis testing (G-test) to ensure that sampling from
+ * the given distributions is distributed properly. The stochastic tests are
+ * slow and their false positive rate is not well suited for CI, so they are
+ * currently disabled-by-default and put into 'tests-slow'.
+ */
+
+#define PROB_DISTR_PRIVATE
+
+#include "orconfig.h"
+
+#include "test/test.h"
+
+#include "core/or/or.h"
+
+#include "lib/math/prob_distr.h"
+#include "lib/math/fp.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "test/rng_test_helpers.h"
+
+#include <float.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Return floor(d) converted to size_t, as a workaround for complaints
+ * under -Wbad-function-cast for (size_t)floor(d).
+ */
+static size_t
+floor_to_size_t(double d)
+{
+ double integral_d = floor(d);
+ return (size_t)integral_d;
+}
+
+/**
+ * Return ceil(d) converted to size_t, as a workaround for complaints
+ * under -Wbad-function-cast for (size_t)ceil(d).
+ */
+static size_t
+ceil_to_size_t(double d)
+{
+ double integral_d = ceil(d);
+ return (size_t)integral_d;
+}
+
+/*
+ * Geometric(p) distribution, supported on {1, 2, 3, ...}.
+ *
+ * Compute the probability mass function Geom(n; p) of the number of
+ * trials before the first success when success has probability p.
+ */
+static double
+logpmf_geometric(unsigned n, double p)
+{
+ /* This is actually a check against 1, but we do >= so that the compiler
+ does not raise a -Wfloat-equal */
+ if (p >= 1) {
+ if (n == 1)
+ return 0;
+ else
+ return -HUGE_VAL;
+ }
+ return (n - 1)*log1p(-p) + log(p);
+}
+
+/**
+ * Compute the logistic function, translated in output by 1/2:
+ * logistichalf(x) = logistic(x) - 1/2. Well-conditioned on the entire
+ * real plane, with maximum condition number 1 at 0.
+ *
+ * This implementation gives relative error bounded by 5 eps.
+ */
+static double
+logistichalf(double x)
+{
+ /*
+ * Rewrite this with the identity
+ *
+ * 1/(1 + e^{-x}) - 1/2
+ * = (1 - 1/2 - e^{-x}/2)/(1 + e^{-x})
+ * = (1/2 - e^{-x}/2)/(1 + e^{-x})
+ * = (1 - e^{-x})/[2 (1 + e^{-x})]
+ * = -(e^{-x} - 1)/[2 (1 + e^{-x})],
+ *
+ * which we can evaluate by -expm1(-x)/[2 (1 + exp(-x))].
+ *
+ * Suppose exp has error d0, + has error d1, expm1 has error
+ * d2, and / has error d3, so we evaluate
+ *
+ * -(1 + d2) (1 + d3) (e^{-x} - 1)
+ * / [2 (1 + d1) (1 + (1 + d0) e^{-x})].
+ *
+ * In the denominator,
+ *
+ * 1 + (1 + d0) e^{-x}
+ * = 1 + e^{-x} + d0 e^{-x}
+ * = (1 + e^{-x}) (1 + d0 e^{-x}/(1 + e^{-x})),
+ *
+ * so the relative error of the numerator is
+ *
+ * d' = d2 + d3 + d2 d3,
+ * and of the denominator,
+ * d'' = d1 + d0 e^{-x}/(1 + e^{-x}) + d0 d1 e^{-x}/(1 + e^{-x})
+ * = d1 + d0 L(-x) + d0 d1 L(-x),
+ *
+ * where L(-x) is logistic(-x). By Lemma 1 the relative error
+ * of the quotient is bounded by
+ *
+ * 2|d2 + d3 + d2 d3 - d1 - d0 L(x) + d0 d1 L(x)|,
+ *
+ * Since 0 < L(x) < 1, this is bounded by
+ *
+ * 2|d2| + 2|d3| + 2|d2 d3| + 2|d1| + 2|d0| + 2|d0 d1|
+ * <= 4 eps + 2 eps^2.
+ */
+ if (x < log(DBL_EPSILON/8)) {
+ /*
+ * Avoid overflow in e^{-x}. When x < log(eps/4), we
+ * we further have x < logit(eps/4), so that
+ * logistic(x) < eps/4. Hence the relative error of
+ * logistic(x) - 1/2 from -1/2 is bounded by eps/2, and
+ * so the relative error of -1/2 from logistic(x) - 1/2
+ * is bounded by eps.
+ */
+ return -0.5;
+ } else {
+ return -expm1(-x)/(2*(1 + exp(-x)));
+ }
+}
+
+/**
+ * Compute the log of the sum of the exps. Caller should arrange the
+ * array in descending order to minimize error because I don't want to
+ * deal with using temporary space and the one caller in this file
+ * arranges that anyway.
+ *
+ * Warning: This implementation does not handle infinite or NaN inputs
+ * sensibly, because I don't need that here at the moment. (NaN, or
+ * -inf and +inf together, should yield NaN; +inf and finite should
+ * yield +inf; otherwise all -inf should be ignored because exp(-inf) =
+ * 0.)
+ */
+static double
+logsumexp(double *A, size_t n)
+{
+ double maximum, sum;
+ size_t i;
+
+ if (n == 0)
+ return log(0);
+
+ maximum = A[0];
+ for (i = 1; i < n; i++) {
+ if (A[i] > maximum)
+ maximum = A[i];
+ }
+
+ sum = 0;
+ for (i = n; i --> 0;)
+ sum += exp(A[i] - maximum);
+
+ return log(sum) + maximum;
+}
+
+/**
+ * Compute log(1 - e^x). Defined only for negative x so that e^x < 1.
+ * This is the complement of a probability in log space.
+ */
+static double
+log1mexp(double x)
+{
+
+ /*
+ * We want to compute log on [0, 1/2) but log1p on [1/2, +inf),
+ * so partition x at -log(2) = log(1/2).
+ */
+ if (-log(2) < x)
+ return log(-expm1(x));
+ else
+ return log1p(-exp(x));
+}
+
+/*
+ * Tests of numerical errors in computing logit, logistic, and the
+ * various cdfs, sfs, icdfs, and isfs.
+ */
+
+#define arraycount(A) (sizeof(A)/sizeof(A[0]))
+
+/** Return relative error between <b>actual</b> and <b>expected</b>.
+ * Special cases: If <b>expected</b> is zero or infinite, return 1 if
+ * <b>actual</b> is equal to <b>expected</b> and 0 if not, since the
+ * usual notion of relative error is undefined but we only use this
+ * for testing relerr(e, a) <= bound. If either is NaN, return NaN,
+ * which has the property that NaN <= bound is false no matter what
+ * bound is.
+ *
+ * Beware: if you test !(relerr(e, a) > bound), then then the result
+ * is true when a is NaN because NaN > bound is false too. See
+ * CHECK_RELERR for correct use to decide when to report failure.
+ */
+static double
+relerr(double expected, double actual)
+{
+ /*
+ * To silence -Wfloat-equal, we have to test for equality using
+ * inequalities: we have (fabs(expected) <= 0) iff (expected == 0),
+ * and (actual <= expected && actual >= expected) iff actual ==
+ * expected whether expected is zero or infinite.
+ */
+ if (fabs(expected) <= 0 || tor_isinf(expected)) {
+ if (actual <= expected && actual >= expected)
+ return 0;
+ else
+ return 1;
+ } else {
+ return fabs((expected - actual)/expected);
+ }
+}
+
+/** Check that relative error of <b>expected</b> and <b>actual</b> is within
+ * <b>relerr_bound</b>. Caller must arrange to have i and relerr_bound in
+ * scope. */
+#define CHECK_RELERR(expected, actual) do { \
+ double check_expected = (expected); \
+ double check_actual = (actual); \
+ const char *str_expected = #expected; \
+ const char *str_actual = #actual; \
+ double check_relerr = relerr(expected, actual); \
+ if (!(relerr(check_expected, check_actual) <= relerr_bound)) { \
+ log_warn(LD_GENERAL, "%s:%d: case %u: relerr(%s=%.17e, %s=%.17e)" \
+ " = %.17e > %.17e\n", \
+ __func__, __LINE__, (unsigned) i, \
+ str_expected, check_expected, \
+ str_actual, check_actual, \
+ check_relerr, relerr_bound); \
+ ok = false; \
+ } \
+} while (0)
+
+/* Check that a <= b.
+ * Caller must arrange to have i in scope. */
+#define CHECK_LE(a, b) do { \
+ double check_a = (a); \
+ double check_b = (b); \
+ const char *str_a = #a; \
+ const char *str_b = #b; \
+ if (!(check_a <= check_b)) { \
+ log_warn(LD_GENERAL, "%s:%d: case %u: %s=%.17e > %s=%.17e\n", \
+ __func__, __LINE__, (unsigned) i, \
+ str_a, check_a, str_b, check_b); \
+ ok = false; \
+ } \
+} while (0)
+
+/**
+ * Test the logit and logistic functions. Confirm that they agree with
+ * the cdf, sf, icdf, and isf of the standard Logistic distribution.
+ * Confirm that the sampler for the standard logistic distribution maps
+ * [0, 1] into the right subinterval for the inverse transform, for
+ * this implementation.
+ */
+static void
+test_logit_logistic(void *arg)
+{
+ (void) arg;
+
+ static const struct {
+ double x; /* x = logit(p) */
+ double p; /* p = logistic(x) */
+ double phalf; /* p - 1/2 = logistic(x) - 1/2 */
+ } cases[] = {
+ { -HUGE_VAL, 0, -0.5 },
+ { -1000, 0, -0.5 },
+ { -710, 4.47628622567513e-309, -0.5 },
+ { -708, 3.307553003638408e-308, -0.5 },
+ { -2, .11920292202211755, -.3807970779778824 },
+ { -1.0000001, .2689414017088022, -.23105859829119776 },
+ { -1, .2689414213699951, -.23105857863000487 },
+ { -0.9999999, .26894144103118883, -.2310585589688111 },
+ /* see src/test/prob_distr_mpfr_ref.c for computation */
+ { -4.000000000537333e-5, .49999, -1.0000000000010001e-5 },
+ { -4.000000000533334e-5, .49999, -.00001 },
+ { -4.000000108916878e-9, .499999999, -1.0000000272292198e-9 },
+ { -4e-9, .499999999, -1e-9 },
+ { -4e-16, .5, -1e-16 },
+ { -4e-300, .5, -1e-300 },
+ { 0, .5, 0 },
+ { 4e-300, .5, 1e-300 },
+ { 4e-16, .5, 1e-16 },
+ { 3.999999886872274e-9, .500000001, 9.999999717180685e-10 },
+ { 4e-9, .500000001, 1e-9 },
+ { 4.0000000005333336e-5, .50001, .00001 },
+ { 8.000042667076272e-3, .502, .002 },
+ { 0.9999999, .7310585589688111, .2310585589688111 },
+ { 1, .7310585786300049, .23105857863000487 },
+ { 1.0000001, .7310585982911977, .23105859829119774 },
+ { 2, .8807970779778823, .3807970779778824 },
+ { 708, 1, .5 },
+ { 710, 1, .5 },
+ { 1000, 1, .5 },
+ { HUGE_VAL, 1, .5 },
+ };
+ double relerr_bound = 3e-15; /* >10eps */
+ size_t i;
+ bool ok = true;
+
+ for (i = 0; i < arraycount(cases); i++) {
+ double x = cases[i].x;
+ double p = cases[i].p;
+ double phalf = cases[i].phalf;
+
+ /*
+ * cdf is logistic, icdf is logit, and symmetry for
+ * sf/isf.
+ */
+ CHECK_RELERR(logistic(x), cdf_logistic(x, 0, 1));
+ CHECK_RELERR(logistic(-x), sf_logistic(x, 0, 1));
+ CHECK_RELERR(logit(p), icdf_logistic(p, 0, 1));
+ CHECK_RELERR(-logit(p), isf_logistic(p, 0, 1));
+
+ CHECK_RELERR(cdf_logistic(x, 0, 1), cdf_logistic(x*2, 0, 2));
+ CHECK_RELERR(sf_logistic(x, 0, 1), sf_logistic(x*2, 0, 2));
+ CHECK_RELERR(icdf_logistic(p, 0, 1), icdf_logistic(p, 0, 2)/2);
+ CHECK_RELERR(isf_logistic(p, 0, 1), isf_logistic(p, 0, 2)/2);
+
+ CHECK_RELERR(cdf_logistic(x, 0, 1), cdf_logistic(x/2, 0, .5));
+ CHECK_RELERR(sf_logistic(x, 0, 1), sf_logistic(x/2, 0, .5));
+ CHECK_RELERR(icdf_logistic(p, 0, 1), icdf_logistic(p, 0,.5)*2);
+ CHECK_RELERR(isf_logistic(p, 0, 1), isf_logistic(p, 0, .5)*2);
+
+ CHECK_RELERR(cdf_logistic(x, 0, 1), cdf_logistic(x*2 + 1, 1, 2));
+ CHECK_RELERR(sf_logistic(x, 0, 1), sf_logistic(x*2 + 1, 1, 2));
+
+ /*
+ * For p near 0 and p near 1/2, the arithmetic of
+ * translating by 1 loses precision.
+ */
+ if (fabs(p) > DBL_EPSILON && fabs(p) < 0.4) {
+ CHECK_RELERR(icdf_logistic(p, 0, 1),
+ (icdf_logistic(p, 1, 2) - 1)/2);
+ CHECK_RELERR(isf_logistic(p, 0, 1),
+ (isf_logistic(p, 1, 2) - 1)/2);
+ }
+
+ CHECK_RELERR(p, logistic(x));
+ CHECK_RELERR(phalf, logistichalf(x));
+
+ /*
+ * On the interior floating-point numbers, either logit or
+ * logithalf had better give the correct answer.
+ *
+ * For probabilities near 0, we can get much finer resolution with
+ * logit, and for probabilities near 1/2, we can get much finer
+ * resolution with logithalf by representing them using p - 1/2.
+ *
+ * E.g., we can write -.00001 for phalf, and .49999 for p, but the
+ * difference 1/2 - .00001 gives 1.0000000000010001e-5 in binary64
+ * arithmetic. So test logit(.49999) which should give the same
+ * answer as logithalf(-1.0000000000010001e-5), namely
+ * -4.000000000537333e-5, and also test logithalf(-.00001) which
+ * gives -4.000000000533334e-5 instead -- but don't expect
+ * logit(.49999) to give -4.000000000533334e-5 even though it looks
+ * like 1/2 - .00001.
+ *
+ * A naive implementation of logit will just use log(p/(1 - p)) and
+ * give the answer -4.000000000551673e-05 for .49999, which is
+ * wrong in a lot of digits, which happens because log is
+ * ill-conditioned near 1 and thus amplifies whatever relative
+ * error we made in computing p/(1 - p).
+ */
+ if ((0 < p && p < 1) || tor_isinf(x)) {
+ if (phalf >= p - 0.5 && phalf <= p - 0.5)
+ CHECK_RELERR(x, logit(p));
+ if (p >= 0.5 + phalf && p <= 0.5 + phalf)
+ CHECK_RELERR(x, logithalf(phalf));
+ }
+
+ CHECK_RELERR(-phalf, logistichalf(-x));
+ if (fabs(phalf) < 0.5 || tor_isinf(x))
+ CHECK_RELERR(-x, logithalf(-phalf));
+ if (p < 1 || tor_isinf(x)) {
+ CHECK_RELERR(1 - p, logistic(-x));
+ if (p > .75 || tor_isinf(x))
+ CHECK_RELERR(-x, logit(1 - p));
+ } else {
+ CHECK_LE(logistic(-x), 1e-300);
+ }
+ }
+
+ for (i = 0; i <= 100; i++) {
+ double p0 = (double)i/100;
+
+ CHECK_RELERR(logit(p0/(1 + M_E)), sample_logistic(0, 0, p0));
+ CHECK_RELERR(-logit(p0/(1 + M_E)), sample_logistic(1, 0, p0));
+ CHECK_RELERR(logithalf(p0*(0.5 - 1/(1 + M_E))),
+ sample_logistic(0, 1, p0));
+ CHECK_RELERR(-logithalf(p0*(0.5 - 1/(1 + M_E))),
+ sample_logistic(1, 1, p0));
+ }
+
+ if (!ok)
+ printf("fail logit/logistic / logistic cdf/sf\n");
+
+ tt_assert(ok);
+
+ done:
+ ;
+}
+
+/**
+ * Test the cdf, sf, icdf, and isf of the LogLogistic distribution.
+ */
+static void
+test_log_logistic(void *arg)
+{
+ (void) arg;
+
+ static const struct {
+ /* x is a point in the support of the LogLogistic distribution */
+ double x;
+ /* 'p' is the probability that a random variable X for a given LogLogistic
+ * probability distribution will take value less-or-equal to x */
+ double p;
+ /* 'np' is the probability that a random variable X for a given LogLogistic
+ * probability distribution will take value greater-or-equal to x. */
+ double np;
+ } cases[] = {
+ { 0, 0, 1 },
+ { 1e-300, 1e-300, 1 },
+ { 1e-17, 1e-17, 1 },
+ { 1e-15, 1e-15, .999999999999999 },
+ { .1, .09090909090909091, .90909090909090909 },
+ { .25, .2, .8 },
+ { .5, .33333333333333333, .66666666666666667 },
+ { .75, .42857142857142855, .5714285714285714 },
+ { .9999, .49997499874993756, .5000250012500626 },
+ { .99999999, .49999999749999996, .5000000025 },
+ { .999999999999999, .49999999999999994, .5000000000000002 },
+ { 1, .5, .5 },
+ };
+ double relerr_bound = 3e-15;
+ size_t i;
+ bool ok = true;
+
+ for (i = 0; i < arraycount(cases); i++) {
+ double x = cases[i].x;
+ double p = cases[i].p;
+ double np = cases[i].np;
+
+ CHECK_RELERR(p, cdf_log_logistic(x, 1, 1));
+ CHECK_RELERR(p, cdf_log_logistic(x/2, .5, 1));
+ CHECK_RELERR(p, cdf_log_logistic(x*2, 2, 1));
+ CHECK_RELERR(p, cdf_log_logistic(sqrt(x), 1, 2));
+ CHECK_RELERR(p, cdf_log_logistic(sqrt(x)/2, .5, 2));
+ CHECK_RELERR(p, cdf_log_logistic(sqrt(x)*2, 2, 2));
+ if (2*sqrt(DBL_MIN) < x) {
+ CHECK_RELERR(p, cdf_log_logistic(x*x, 1, .5));
+ CHECK_RELERR(p, cdf_log_logistic(x*x/2, .5, .5));
+ CHECK_RELERR(p, cdf_log_logistic(x*x*2, 2, .5));
+ }
+
+ CHECK_RELERR(np, sf_log_logistic(x, 1, 1));
+ CHECK_RELERR(np, sf_log_logistic(x/2, .5, 1));
+ CHECK_RELERR(np, sf_log_logistic(x*2, 2, 1));
+ CHECK_RELERR(np, sf_log_logistic(sqrt(x), 1, 2));
+ CHECK_RELERR(np, sf_log_logistic(sqrt(x)/2, .5, 2));
+ CHECK_RELERR(np, sf_log_logistic(sqrt(x)*2, 2, 2));
+ if (2*sqrt(DBL_MIN) < x) {
+ CHECK_RELERR(np, sf_log_logistic(x*x, 1, .5));
+ CHECK_RELERR(np, sf_log_logistic(x*x/2, .5, .5));
+ CHECK_RELERR(np, sf_log_logistic(x*x*2, 2, .5));
+ }
+
+ CHECK_RELERR(np, cdf_log_logistic(1/x, 1, 1));
+ CHECK_RELERR(np, cdf_log_logistic(1/(2*x), .5, 1));
+ CHECK_RELERR(np, cdf_log_logistic(2/x, 2, 1));
+ CHECK_RELERR(np, cdf_log_logistic(1/sqrt(x), 1, 2));
+ CHECK_RELERR(np, cdf_log_logistic(1/(2*sqrt(x)), .5, 2));
+ CHECK_RELERR(np, cdf_log_logistic(2/sqrt(x), 2, 2));
+ if (2*sqrt(DBL_MIN) < x && x < 1/(2*sqrt(DBL_MIN))) {
+ CHECK_RELERR(np, cdf_log_logistic(1/(x*x), 1, .5));
+ CHECK_RELERR(np, cdf_log_logistic(1/(2*x*x), .5, .5));
+ CHECK_RELERR(np, cdf_log_logistic(2/(x*x), 2, .5));
+ }
+
+ CHECK_RELERR(p, sf_log_logistic(1/x, 1, 1));
+ CHECK_RELERR(p, sf_log_logistic(1/(2*x), .5, 1));
+ CHECK_RELERR(p, sf_log_logistic(2/x, 2, 1));
+ CHECK_RELERR(p, sf_log_logistic(1/sqrt(x), 1, 2));
+ CHECK_RELERR(p, sf_log_logistic(1/(2*sqrt(x)), .5, 2));
+ CHECK_RELERR(p, sf_log_logistic(2/sqrt(x), 2, 2));
+ if (2*sqrt(DBL_MIN) < x && x < 1/(2*sqrt(DBL_MIN))) {
+ CHECK_RELERR(p, sf_log_logistic(1/(x*x), 1, .5));
+ CHECK_RELERR(p, sf_log_logistic(1/(2*x*x), .5, .5));
+ CHECK_RELERR(p, sf_log_logistic(2/(x*x), 2, .5));
+ }
+
+ CHECK_RELERR(x, icdf_log_logistic(p, 1, 1));
+ CHECK_RELERR(x/2, icdf_log_logistic(p, .5, 1));
+ CHECK_RELERR(x*2, icdf_log_logistic(p, 2, 1));
+ CHECK_RELERR(x, icdf_log_logistic(p, 1, 1));
+ CHECK_RELERR(sqrt(x)/2, icdf_log_logistic(p, .5, 2));
+ CHECK_RELERR(sqrt(x)*2, icdf_log_logistic(p, 2, 2));
+ CHECK_RELERR(sqrt(x), icdf_log_logistic(p, 1, 2));
+ CHECK_RELERR(x*x/2, icdf_log_logistic(p, .5, .5));
+ CHECK_RELERR(x*x*2, icdf_log_logistic(p, 2, .5));
+
+ if (np < .9) {
+ CHECK_RELERR(x, isf_log_logistic(np, 1, 1));
+ CHECK_RELERR(x/2, isf_log_logistic(np, .5, 1));
+ CHECK_RELERR(x*2, isf_log_logistic(np, 2, 1));
+ CHECK_RELERR(sqrt(x), isf_log_logistic(np, 1, 2));
+ CHECK_RELERR(sqrt(x)/2, isf_log_logistic(np, .5, 2));
+ CHECK_RELERR(sqrt(x)*2, isf_log_logistic(np, 2, 2));
+ CHECK_RELERR(x*x, isf_log_logistic(np, 1, .5));
+ CHECK_RELERR(x*x/2, isf_log_logistic(np, .5, .5));
+ CHECK_RELERR(x*x*2, isf_log_logistic(np, 2, .5));
+
+ CHECK_RELERR(1/x, icdf_log_logistic(np, 1, 1));
+ CHECK_RELERR(1/(2*x), icdf_log_logistic(np, .5, 1));
+ CHECK_RELERR(2/x, icdf_log_logistic(np, 2, 1));
+ CHECK_RELERR(1/sqrt(x), icdf_log_logistic(np, 1, 2));
+ CHECK_RELERR(1/(2*sqrt(x)),
+ icdf_log_logistic(np, .5, 2));
+ CHECK_RELERR(2/sqrt(x), icdf_log_logistic(np, 2, 2));
+ CHECK_RELERR(1/(x*x), icdf_log_logistic(np, 1, .5));
+ CHECK_RELERR(1/(2*x*x), icdf_log_logistic(np, .5, .5));
+ CHECK_RELERR(2/(x*x), icdf_log_logistic(np, 2, .5));
+ }
+
+ CHECK_RELERR(1/x, isf_log_logistic(p, 1, 1));
+ CHECK_RELERR(1/(2*x), isf_log_logistic(p, .5, 1));
+ CHECK_RELERR(2/x, isf_log_logistic(p, 2, 1));
+ CHECK_RELERR(1/sqrt(x), isf_log_logistic(p, 1, 2));
+ CHECK_RELERR(1/(2*sqrt(x)), isf_log_logistic(p, .5, 2));
+ CHECK_RELERR(2/sqrt(x), isf_log_logistic(p, 2, 2));
+ CHECK_RELERR(1/(x*x), isf_log_logistic(p, 1, .5));
+ CHECK_RELERR(1/(2*x*x), isf_log_logistic(p, .5, .5));
+ CHECK_RELERR(2/(x*x), isf_log_logistic(p, 2, .5));
+ }
+
+ for (i = 0; i <= 100; i++) {
+ double p0 = (double)i/100;
+
+ CHECK_RELERR(0.5*p0/(1 - 0.5*p0), sample_log_logistic(0, p0));
+ CHECK_RELERR((1 - 0.5*p0)/(0.5*p0),
+ sample_log_logistic(1, p0));
+ }
+
+ if (!ok)
+ printf("fail log logistic cdf/sf\n");
+
+ tt_assert(ok);
+
+ done:
+ ;
+}
+
+/**
+ * Test the cdf, sf, icdf, isf of the Weibull distribution.
+ */
+static void
+test_weibull(void *arg)
+{
+ (void) arg;
+
+ static const struct {
+ /* x is a point in the support of the Weibull distribution */
+ double x;
+ /* 'p' is the probability that a random variable X for a given Weibull
+ * probability distribution will take value less-or-equal to x */
+ double p;
+ /* 'np' is the probability that a random variable X for a given Weibull
+ * probability distribution will take value greater-or-equal to x. */
+ double np;
+ } cases[] = {
+ { 0, 0, 1 },
+ { 1e-300, 1e-300, 1 },
+ { 1e-17, 1e-17, 1 },
+ { .1, .09516258196404043, .9048374180359595 },
+ { .5, .3934693402873666, .6065306597126334 },
+ { .6931471805599453, .5, .5 },
+ { 1, .6321205588285577, .36787944117144233 },
+ { 10, .9999546000702375, 4.5399929762484854e-5 },
+ { 36, .9999999999999998, 2.319522830243569e-16 },
+ { 37, .9999999999999999, 8.533047625744066e-17 },
+ { 38, 1, 3.1391327920480296e-17 },
+ { 100, 1, 3.720075976020836e-44 },
+ { 708, 1, 3.307553003638408e-308 },
+ { 710, 1, 4.47628622567513e-309 },
+ { 1000, 1, 0 },
+ { HUGE_VAL, 1, 0 },
+ };
+ double relerr_bound = 3e-15;
+ size_t i;
+ bool ok = true;
+
+ for (i = 0; i < arraycount(cases); i++) {
+ double x = cases[i].x;
+ double p = cases[i].p;
+ double np = cases[i].np;
+
+ CHECK_RELERR(p, cdf_weibull(x, 1, 1));
+ CHECK_RELERR(p, cdf_weibull(x/2, .5, 1));
+ CHECK_RELERR(p, cdf_weibull(x*2, 2, 1));
+ /* For 0 < x < sqrt(DBL_MIN), x^2 loses lots of bits. */
+ if (x <= 0 ||
+ sqrt(DBL_MIN) <= x) {
+ CHECK_RELERR(p, cdf_weibull(x*x, 1, .5));
+ CHECK_RELERR(p, cdf_weibull(x*x/2, .5, .5));
+ CHECK_RELERR(p, cdf_weibull(x*x*2, 2, .5));
+ }
+ CHECK_RELERR(p, cdf_weibull(sqrt(x), 1, 2));
+ CHECK_RELERR(p, cdf_weibull(sqrt(x)/2, .5, 2));
+ CHECK_RELERR(p, cdf_weibull(sqrt(x)*2, 2, 2));
+ CHECK_RELERR(np, sf_weibull(x, 1, 1));
+ CHECK_RELERR(np, sf_weibull(x/2, .5, 1));
+ CHECK_RELERR(np, sf_weibull(x*2, 2, 1));
+ CHECK_RELERR(np, sf_weibull(x*x, 1, .5));
+ CHECK_RELERR(np, sf_weibull(x*x/2, .5, .5));
+ CHECK_RELERR(np, sf_weibull(x*x*2, 2, .5));
+ if (x >= 10) {
+ /*
+ * exp amplifies the error of sqrt(x)^2
+ * proportionally to exp(x); for large inputs
+ * this is significant.
+ */
+ double t = -expm1(-x*(2*DBL_EPSILON + DBL_EPSILON));
+ relerr_bound = t + DBL_EPSILON + t*DBL_EPSILON;
+ if (relerr_bound < 3e-15)
+ /*
+ * The tests are written only to 16
+ * decimal places anyway even if your
+ * `double' is, say, i387 binary80, for
+ * whatever reason.
+ */
+ relerr_bound = 3e-15;
+ CHECK_RELERR(np, sf_weibull(sqrt(x), 1, 2));
+ CHECK_RELERR(np, sf_weibull(sqrt(x)/2, .5, 2));
+ CHECK_RELERR(np, sf_weibull(sqrt(x)*2, 2, 2));
+ }
+
+ if (p <= 0.75) {
+ /*
+ * For p near 1, not enough precision near 1 to
+ * recover x.
+ */
+ CHECK_RELERR(x, icdf_weibull(p, 1, 1));
+ CHECK_RELERR(x/2, icdf_weibull(p, .5, 1));
+ CHECK_RELERR(x*2, icdf_weibull(p, 2, 1));
+ }
+ if (p >= 0.25 && !tor_isinf(x) && np > 0) {
+ /*
+ * For p near 0, not enough precision in np
+ * near 1 to recover x. For 0, isf gives inf,
+ * even if p is precise enough for the icdf to
+ * work.
+ */
+ CHECK_RELERR(x, isf_weibull(np, 1, 1));
+ CHECK_RELERR(x/2, isf_weibull(np, .5, 1));
+ CHECK_RELERR(x*2, isf_weibull(np, 2, 1));
+ }
+ }
+
+ for (i = 0; i <= 100; i++) {
+ double p0 = (double)i/100;
+
+ CHECK_RELERR(3*sqrt(-log(p0/2)), sample_weibull(0, p0, 3, 2));
+ CHECK_RELERR(3*sqrt(-log1p(-p0/2)),
+ sample_weibull(1, p0, 3, 2));
+ }
+
+ if (!ok)
+ printf("fail Weibull cdf/sf\n");
+
+ tt_assert(ok);
+
+ done:
+ ;
+}
+
+/**
+ * Test the cdf, sf, icdf, and isf of the generalized Pareto
+ * distribution.
+ */
+static void
+test_genpareto(void *arg)
+{
+ (void) arg;
+
+ struct {
+ /* xi is the 'xi' parameter of the generalized Pareto distribution, and the
+ * rest are the same as in the above tests */
+ double xi, x, p, np;
+ } cases[] = {
+ { 0, 0, 0, 1 },
+ { 1e-300, .004, 3.992010656008528e-3, .9960079893439915 },
+ { 1e-300, .1, .09516258196404043, .9048374180359595 },
+ { 1e-300, 1, .6321205588285577, .36787944117144233 },
+ { 1e-300, 10, .9999546000702375, 4.5399929762484854e-5 },
+ { 1e-200, 1e-16, 9.999999999999999e-17, .9999999999999999 },
+ { 1e-16, 1e-200, 9.999999999999998e-201, 1 },
+ { 1e-16, 1e-16, 1e-16, 1 },
+ { 1e-16, .004, 3.992010656008528e-3, .9960079893439915 },
+ { 1e-16, .1, .09516258196404043, .9048374180359595 },
+ { 1e-16, 1, .6321205588285577, .36787944117144233 },
+ { 1e-16, 10, .9999546000702375, 4.539992976248509e-5 },
+ { 1e-10, 1e-6, 9.999995000001667e-7, .9999990000005 },
+ { 1e-8, 1e-8, 9.999999950000001e-9, .9999999900000001 },
+ { 1, 1e-300, 1e-300, 1 },
+ { 1, 1e-16, 1e-16, .9999999999999999 },
+ { 1, .1, .09090909090909091, .9090909090909091 },
+ { 1, 1, .5, .5 },
+ { 1, 10, .9090909090909091, .0909090909090909 },
+ { 1, 100, .9900990099009901, .0099009900990099 },
+ { 1, 1000, .999000999000999, 9.990009990009992e-4 },
+ { 10, 1e-300, 1e-300, 1 },
+ { 10, 1e-16, 9.999999999999995e-17, .9999999999999999 },
+ { 10, .1, .06696700846319258, .9330329915368074 },
+ { 10, 1, .21320655780322778, .7867934421967723 },
+ { 10, 10, .3696701667040189, .6303298332959811 },
+ { 10, 100, .49886285755007337, .5011371424499267 },
+ { 10, 1000, .6018968102992647, .3981031897007353 },
+ };
+ double xi_array[] = { -1.5, -1, -1e-30, 0, 1e-30, 1, 1.5 };
+ size_t i, j;
+ double relerr_bound = 3e-15;
+ bool ok = true;
+
+ for (i = 0; i < arraycount(cases); i++) {
+ double xi = cases[i].xi;
+ double x = cases[i].x;
+ double p = cases[i].p;
+ double np = cases[i].np;
+
+ CHECK_RELERR(p, cdf_genpareto(x, 0, 1, xi));
+ CHECK_RELERR(p, cdf_genpareto(x*2, 0, 2, xi));
+ CHECK_RELERR(p, cdf_genpareto(x/2, 0, .5, xi));
+ CHECK_RELERR(np, sf_genpareto(x, 0, 1, xi));
+ CHECK_RELERR(np, sf_genpareto(x*2, 0, 2, xi));
+ CHECK_RELERR(np, sf_genpareto(x/2, 0, .5, xi));
+
+ if (p < .5) {
+ CHECK_RELERR(x, icdf_genpareto(p, 0, 1, xi));
+ CHECK_RELERR(x*2, icdf_genpareto(p, 0, 2, xi));
+ CHECK_RELERR(x/2, icdf_genpareto(p, 0, .5, xi));
+ }
+ if (np < .5) {
+ CHECK_RELERR(x, isf_genpareto(np, 0, 1, xi));
+ CHECK_RELERR(x*2, isf_genpareto(np, 0, 2, xi));
+ CHECK_RELERR(x/2, isf_genpareto(np, 0, .5, xi));
+ }
+ }
+
+ for (i = 0; i < arraycount(xi_array); i++) {
+ for (j = 0; j <= 100; j++) {
+ double p0 = (j == 0 ? 2*DBL_MIN : (double)j/100);
+
+ /* This is actually a check against 0, but we do <= so that the compiler
+ does not raise a -Wfloat-equal */
+ if (fabs(xi_array[i]) <= 0) {
+ /*
+ * When xi == 0, the generalized Pareto
+ * distribution reduces to an
+ * exponential distribution.
+ */
+ CHECK_RELERR(-log(p0/2),
+ sample_genpareto(0, p0, 0));
+ CHECK_RELERR(-log1p(-p0/2),
+ sample_genpareto(1, p0, 0));
+ } else {
+ CHECK_RELERR(expm1(-xi_array[i]*log(p0/2))/xi_array[i],
+ sample_genpareto(0, p0, xi_array[i]));
+ CHECK_RELERR((j == 0 ? DBL_MIN :
+ expm1(-xi_array[i]*log1p(-p0/2))/xi_array[i]),
+ sample_genpareto(1, p0, xi_array[i]));
+ }
+
+ CHECK_RELERR(isf_genpareto(p0/2, 0, 1, xi_array[i]),
+ sample_genpareto(0, p0, xi_array[i]));
+ CHECK_RELERR(icdf_genpareto(p0/2, 0, 1, xi_array[i]),
+ sample_genpareto(1, p0, xi_array[i]));
+ }
+ }
+
+ tt_assert(ok);
+
+ done:
+ ;
+}
+
+/**
+ * Test the deterministic sampler for uniform distribution on [a, b].
+ *
+ * This currently only tests whether the outcome lies within [a, b].
+ */
+static void
+test_uniform_interval(void *arg)
+{
+ (void) arg;
+ struct {
+ /* Sample from a uniform distribution with parameters 'a' and 'b', using
+ * 't' as the sampling index. */
+ double t, a, b;
+ } cases[] = {
+ { 0, 0, 0 },
+ { 0, 0, 1 },
+ { 0, 1.0000000000000007, 3.999999999999995 },
+ { 0, 4000, 4000 },
+ { 0.42475836677491291, 4000, 4000 },
+ { 0, -DBL_MAX, DBL_MAX },
+ { 0.25, -DBL_MAX, DBL_MAX },
+ { 0.5, -DBL_MAX, DBL_MAX },
+ };
+ size_t i = 0;
+ bool ok = true;
+
+ for (i = 0; i < arraycount(cases); i++) {
+ double t = cases[i].t;
+ double a = cases[i].a;
+ double b = cases[i].b;
+
+ CHECK_LE(a, sample_uniform_interval(t, a, b));
+ CHECK_LE(sample_uniform_interval(t, a, b), b);
+
+ CHECK_LE(a, sample_uniform_interval(1 - t, a, b));
+ CHECK_LE(sample_uniform_interval(1 - t, a, b), b);
+
+ CHECK_LE(sample_uniform_interval(t, -b, -a), -a);
+ CHECK_LE(-b, sample_uniform_interval(t, -b, -a));
+
+ CHECK_LE(sample_uniform_interval(1 - t, -b, -a), -a);
+ CHECK_LE(-b, sample_uniform_interval(1 - t, -b, -a));
+ }
+
+ tt_assert(ok);
+
+ done:
+ ;
+}
+
+/********************** Stochastic tests ****************************/
+
+/*
+ * Psi test, sometimes also called G-test. The psi test statistic,
+ * suitably scaled, has chi^2 distribution, but the psi test tends to
+ * have better statistical power in practice to detect deviations than
+ * the chi^2 test does. (The chi^2 test statistic is the first term of
+ * the Taylor expansion of the psi test statistic.) The psi test is
+ * generic, for any CDF; particular distributions might have higher-
+ * power tests to distinguish them from predictable deviations or bugs.
+ *
+ * We choose the psi critical value so that a single psi test has
+ * probability below alpha = 1% of spuriously failing even if all the
+ * code is correct. But the false positive rate for a suite of n tests
+ * is higher: 1 - Binom(0; n, alpha) = 1 - (1 - alpha)^n. For n = 10,
+ * this is about 10%, and for n = 100 it is well over 50%.
+ *
+ * Given that these tests will run with every CI job, we want to drive down the
+ * false positive rate. We can drive it down by running each test four times,
+ * and accepting it if it passes at least once; in that case, it is as if we
+ * used Binom(4; 2, alpha) = alpha^4 as the false positive rate for each test,
+ * and for n = 10 tests, it would be 9.99999959506e-08. If each CI build has 14
+ * jobs, then the chance of a CI build failing is 1.39999903326e-06, which
+ * means that a CI build will break with probability 50% after about 495106
+ * builds.
+ *
+ * The critical value for a chi^2 distribution with 100 degrees of
+ * freedom and false positive rate alpha = 1% was taken from:
+ *
+ * NIST/SEMATECH e-Handbook of Statistical Methods, Section
+ * 1.3.6.7.4 `Critical Values of the Chi-Square Distribution',
+ * <https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm>,
+ * retrieved 2018-10-28.
+ */
+
+static const size_t NSAMPLES = 100000;
+/* Number of chances we give to the test to succeed. */
+static const unsigned NTRIALS = 4;
+/* Number of times we want the test to pass per NTRIALS. */
+static const unsigned NPASSES_MIN = 1;
+
+#define PSI_DF 100 /* degrees of freedom */
+static const double PSI_CRITICAL = 135.807; /* critical value, alpha = .01 */
+
+/**
+ * Perform a psi test on an array of sample counts, C, adding up to N
+ * samples, and an array of log expected probabilities, logP,
+ * representing the null hypothesis for the distribution of samples
+ * counted. Return false if the psi test rejects the null hypothesis,
+ * true if otherwise.
+ */
+static bool
+psi_test(const size_t C[PSI_DF], const double logP[PSI_DF], size_t N)
+{
+ double psi = 0;
+ double c = 0; /* Kahan compensation */
+ double t, u;
+ size_t i;
+
+ for (i = 0; i < PSI_DF; i++) {
+ /*
+ * c*log(c/(n*p)) = (1/n) * f*log(f/p) where f = c/n is
+ * the frequency, and f*log(f/p) ---> 0 as f ---> 0, so
+ * this is a reasonable choice. Further, any mass that
+ * _fails_ to turn up in this bin will inflate another
+ * bin instead, so we don't really lose anything by
+ * ignoring empty bins even if they have high
+ * probability.
+ */
+ if (C[i] == 0)
+ continue;
+ t = C[i]*(log((double)C[i]/N) - logP[i]) - c;
+ u = psi + t;
+ c = (u - psi) - t;
+ psi = u;
+ }
+ psi *= 2;
+
+ return psi <= PSI_CRITICAL;
+}
+
+static bool
+test_stochastic_geometric_impl(double p)
+{
+ const struct geometric_t geometric = {
+ .base = GEOMETRIC(geometric),
+ .p = p,
+ };
+ double logP[PSI_DF] = {0};
+ unsigned ntry = NTRIALS, npass = 0;
+ unsigned i;
+ size_t j;
+
+ /* Compute logP[i] = Geom(i + 1; p). */
+ for (i = 0; i < PSI_DF - 1; i++)
+ logP[i] = logpmf_geometric(i + 1, p);
+
+ /* Compute logP[n-1] = log (1 - (P[0] + P[1] + ... + P[n-2])). */
+ logP[PSI_DF - 1] = log1mexp(logsumexp(logP, PSI_DF - 1));
+
+ while (ntry --> 0) {
+ size_t C[PSI_DF] = {0};
+
+ for (j = 0; j < NSAMPLES; j++) {
+ double n_tmp = dist_sample(&geometric.base);
+
+ /* Must be an integer. (XXX -Wfloat-equal) */
+ tor_assert(ceil(n_tmp) <= n_tmp && ceil(n_tmp) >= n_tmp);
+
+ /* Must be a positive integer. */
+ tor_assert(n_tmp >= 1);
+
+ /* Probability of getting a value in the billions is negligible. */
+ tor_assert(n_tmp <= (double)UINT_MAX);
+
+ unsigned n = (unsigned) n_tmp;
+
+ if (n > PSI_DF)
+ n = PSI_DF;
+ C[n - 1]++;
+ }
+
+ if (psi_test(C, logP, NSAMPLES)) {
+ if (++npass >= NPASSES_MIN)
+ break;
+ }
+ }
+
+ if (npass >= NPASSES_MIN) {
+ /* printf("pass %s sampler\n", "geometric"); */
+ return true;
+ } else {
+ printf("fail %s sampler\n", "geometric");
+ return false;
+ }
+}
+
+/**
+ * Divide the support of <b>dist</b> into histogram bins in <b>logP</b>. Start
+ * at the 1st percentile and ending at the 99th percentile. Pick the bin
+ * boundaries using linear interpolation so that they are uniformly spaced.
+ *
+ * In each bin logP[i] we insert the expected log-probability that a sampled
+ * value will fall into that bin. We will use this as the null hypothesis of
+ * the psi test.
+ *
+ * Set logP[i] = log(CDF(x_i) - CDF(x_{i-1})), where x_-1 = -inf, x_n =
+ * +inf, and x_i = i*(hi - lo)/(n - 2).
+ */
+static void
+bin_cdfs(const struct dist_t *dist, double lo, double hi, double *logP,
+ size_t n)
+{
+#define CDF(x) dist_cdf(dist, x)
+#define SF(x) dist_sf(dist, x)
+ const double w = (hi - lo)/(n - 2);
+ double halfway = dist_icdf(dist, 0.5);
+ double x_0, x_1;
+ size_t i;
+ size_t n2 = ceil_to_size_t((halfway - lo)/w);
+
+ tor_assert(lo <= halfway);
+ tor_assert(halfway <= hi);
+ tor_assert(n2 <= n);
+
+ x_1 = lo;
+ logP[0] = log(CDF(x_1) - 0); /* 0 = CDF(-inf) */
+ for (i = 1; i < n2; i++) {
+ x_0 = x_1;
+ /* do the linear interpolation */
+ x_1 = (i <= n/2 ? lo + i*w : hi - (n - 2 - i)*w);
+ /* set the expected log-probability */
+ logP[i] = log(CDF(x_1) - CDF(x_0));
+ }
+ x_0 = hi;
+ logP[n - 1] = log(SF(x_0) - 0); /* 0 = SF(+inf) = 1 - CDF(+inf) */
+
+ /* In this loop we are filling out the high part of the array. We are using
+ * SF because in these cases the CDF is near 1 where precision is lower. So
+ * instead we are using SF near 0 where the precision is higher. We have
+ * SF(t) = 1 - CDF(t). */
+ for (i = 1; i < n - n2; i++) {
+ x_1 = x_0;
+ /* do the linear interpolation */
+ x_0 = (i <= n/2 ? hi - i*w : lo + (n - 2 - i)*w);
+ /* set the expected log-probability */
+ logP[n - i - 1] = log(SF(x_0) - SF(x_1));
+ }
+#undef SF
+#undef CDF
+}
+
+/**
+ * Draw NSAMPLES samples from dist, counting the number of samples x in
+ * the ith bin C[i] if x_{i-1} <= x < x_i, where x_-1 = -inf, x_n =
+ * +inf, and x_i = i*(hi - lo)/(n - 2).
+ */
+static void
+bin_samples(const struct dist_t *dist, double lo, double hi, size_t *C,
+ size_t n)
+{
+ const double w = (hi - lo)/(n - 2);
+ size_t i;
+
+ for (i = 0; i < NSAMPLES; i++) {
+ double x = dist_sample(dist);
+ size_t bin;
+
+ if (x < lo)
+ bin = 0;
+ else if (x < hi)
+ bin = 1 + floor_to_size_t((x - lo)/w);
+ else
+ bin = n - 1;
+ tor_assert(bin < n);
+ C[bin]++;
+ }
+}
+
+/**
+ * Carry out a Psi test on <b>dist</b>.
+ *
+ * Sample NSAMPLES from dist, putting them in bins from -inf to lo to
+ * hi to +inf, and apply up to two psi tests. True if at least one psi
+ * test passes; false if not. False positive rate should be bounded by
+ * 0.01^2 = 0.0001.
+ */
+static bool
+test_psi_dist_sample(const struct dist_t *dist)
+{
+ double logP[PSI_DF] = {0};
+ unsigned ntry = NTRIALS, npass = 0;
+ double lo = dist_icdf(dist, 1/(double)(PSI_DF + 2));
+ double hi = dist_isf(dist, 1/(double)(PSI_DF + 2));
+
+ /* Create the null hypothesis in logP */
+ bin_cdfs(dist, lo, hi, logP, PSI_DF);
+
+ /* Now run the test */
+ while (ntry --> 0) {
+ size_t C[PSI_DF] = {0};
+ bin_samples(dist, lo, hi, C, PSI_DF);
+ if (psi_test(C, logP, NSAMPLES)) {
+ if (++npass >= NPASSES_MIN)
+ break;
+ }
+ }
+
+ /* Did we fail or succeed? */
+ if (npass >= NPASSES_MIN) {
+ /* printf("pass %s sampler\n", dist_name(dist));*/
+ return true;
+ } else {
+ printf("fail %s sampler\n", dist_name(dist));
+ return false;
+ }
+}
+
+static void
+write_stochastic_warning(void)
+{
+ if (tinytest_cur_test_has_failed()) {
+ printf("\n"
+ "NOTE: This is a stochastic test, and we expect it to fail from\n"
+ "time to time, with some low probability. If you see it fail more\n"
+ "than one trial in 100, though, please tell us.\n\n");
+ }
+}
+
+static void
+test_stochastic_uniform(void *arg)
+{
+ (void) arg;
+
+ const struct uniform_t uniform01 = {
+ .base = UNIFORM(uniform01),
+ .a = 0,
+ .b = 1,
+ };
+ const struct uniform_t uniform_pos = {
+ .base = UNIFORM(uniform_pos),
+ .a = 1.23,
+ .b = 4.56,
+ };
+ const struct uniform_t uniform_neg = {
+ .base = UNIFORM(uniform_neg),
+ .a = -10,
+ .b = -1,
+ };
+ const struct uniform_t uniform_cross = {
+ .base = UNIFORM(uniform_cross),
+ .a = -1.23,
+ .b = 4.56,
+ };
+ const struct uniform_t uniform_subnormal = {
+ .base = UNIFORM(uniform_subnormal),
+ .a = 4e-324,
+ .b = 4e-310,
+ };
+ const struct uniform_t uniform_subnormal_cross = {
+ .base = UNIFORM(uniform_subnormal_cross),
+ .a = -4e-324,
+ .b = 4e-310,
+ };
+ bool ok = true, tests_failed = true;
+
+ testing_enable_reproducible_rng();
+
+ ok &= test_psi_dist_sample(&uniform01.base);
+ ok &= test_psi_dist_sample(&uniform_pos.base);
+ ok &= test_psi_dist_sample(&uniform_neg.base);
+ ok &= test_psi_dist_sample(&uniform_cross.base);
+ ok &= test_psi_dist_sample(&uniform_subnormal.base);
+ ok &= test_psi_dist_sample(&uniform_subnormal_cross.base);
+
+ tt_assert(ok);
+
+ tests_failed = false;
+
+ done:
+ if (tests_failed) {
+ write_stochastic_warning();
+ }
+ testing_disable_reproducible_rng();
+}
+
+static bool
+test_stochastic_logistic_impl(double mu, double sigma)
+{
+ const struct logistic_t dist = {
+ .base = LOGISTIC(dist),
+ .mu = mu,
+ .sigma = sigma,
+ };
+
+ /* XXX Consider some fancier logistic test. */
+ return test_psi_dist_sample(&dist.base);
+}
+
+static bool
+test_stochastic_log_logistic_impl(double alpha, double beta)
+{
+ const struct log_logistic_t dist = {
+ .base = LOG_LOGISTIC(dist),
+ .alpha = alpha,
+ .beta = beta,
+ };
+
+ /* XXX Consider some fancier log logistic test. */
+ return test_psi_dist_sample(&dist.base);
+}
+
+static bool
+test_stochastic_weibull_impl(double lambda, double k)
+{
+ const struct weibull_t dist = {
+ .base = WEIBULL(dist),
+ .lambda = lambda,
+ .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
+ */
+// clang-format on
+ return test_psi_dist_sample(&dist.base);
+}
+
+static bool
+test_stochastic_genpareto_impl(double mu, double sigma, double xi)
+{
+ const struct genpareto_t dist = {
+ .base = GENPARETO(dist),
+ .mu = mu,
+ .sigma = sigma,
+ .xi = xi,
+ };
+
+ /* XXX Consider some fancier GPD test. */
+ return test_psi_dist_sample(&dist.base);
+}
+
+static void
+test_stochastic_genpareto(void *arg)
+{
+ bool ok = 0;
+ bool tests_failed = true;
+ (void) arg;
+
+ testing_enable_reproducible_rng();
+
+ ok = test_stochastic_genpareto_impl(0, 1, -0.25);
+ tt_assert(ok);
+ ok = test_stochastic_genpareto_impl(0, 1, -1e-30);
+ tt_assert(ok);
+ ok = test_stochastic_genpareto_impl(0, 1, 0);
+ tt_assert(ok);
+ ok = test_stochastic_genpareto_impl(0, 1, 1e-30);
+ tt_assert(ok);
+ ok = test_stochastic_genpareto_impl(0, 1, 0.25);
+ tt_assert(ok);
+ ok = test_stochastic_genpareto_impl(-1, 1, -0.25);
+ tt_assert(ok);
+ ok = test_stochastic_genpareto_impl(1, 2, 0.25);
+ tt_assert(ok);
+
+ tests_failed = false;
+
+ done:
+ if (tests_failed) {
+ write_stochastic_warning();
+ }
+ testing_disable_reproducible_rng();
+}
+
+static void
+test_stochastic_geometric(void *arg)
+{
+ bool ok = 0;
+ bool tests_failed = true;
+
+ (void) arg;
+
+ testing_enable_reproducible_rng();
+
+ ok = test_stochastic_geometric_impl(0.1);
+ tt_assert(ok);
+ ok = test_stochastic_geometric_impl(0.5);
+ tt_assert(ok);
+ ok = test_stochastic_geometric_impl(0.9);
+ tt_assert(ok);
+ ok = test_stochastic_geometric_impl(1);
+ tt_assert(ok);
+
+ tests_failed = false;
+
+ done:
+ if (tests_failed) {
+ write_stochastic_warning();
+ }
+ testing_disable_reproducible_rng();
+}
+
+static void
+test_stochastic_logistic(void *arg)
+{
+ bool ok = 0;
+ bool tests_failed = true;
+ (void) arg;
+
+ testing_enable_reproducible_rng();
+
+ ok = test_stochastic_logistic_impl(0, 1);
+ tt_assert(ok);
+ ok = test_stochastic_logistic_impl(0, 1e-16);
+ tt_assert(ok);
+ ok = test_stochastic_logistic_impl(1, 10);
+ tt_assert(ok);
+ ok = test_stochastic_logistic_impl(-10, 100);
+ tt_assert(ok);
+
+ tests_failed = false;
+
+ done:
+ if (tests_failed) {
+ write_stochastic_warning();
+ }
+ testing_disable_reproducible_rng();
+}
+
+static void
+test_stochastic_log_logistic(void *arg)
+{
+ bool ok = 0;
+ (void) arg;
+
+ testing_enable_reproducible_rng();
+
+ ok = test_stochastic_log_logistic_impl(1, 1);
+ tt_assert(ok);
+ ok = test_stochastic_log_logistic_impl(1, 10);
+ tt_assert(ok);
+ ok = test_stochastic_log_logistic_impl(M_E, 1e-1);
+ tt_assert(ok);
+ ok = test_stochastic_log_logistic_impl(exp(-10), 1e-2);
+ tt_assert(ok);
+
+ done:
+ write_stochastic_warning();
+ testing_disable_reproducible_rng();
+}
+
+static void
+test_stochastic_weibull(void *arg)
+{
+ bool ok = 0;
+ (void) arg;
+
+ testing_enable_reproducible_rng();
+
+ ok = test_stochastic_weibull_impl(1, 0.5);
+ tt_assert(ok);
+ ok = test_stochastic_weibull_impl(1, 1);
+ tt_assert(ok);
+ ok = test_stochastic_weibull_impl(1, 1.5);
+ tt_assert(ok);
+ ok = test_stochastic_weibull_impl(1, 2);
+ tt_assert(ok);
+ ok = test_stochastic_weibull_impl(10, 1);
+ tt_assert(ok);
+
+ done:
+ write_stochastic_warning();
+ testing_disable_reproducible_rng();
+ UNMOCK(crypto_rand);
+}
+
+struct testcase_t prob_distr_tests[] = {
+ { "logit_logistics", test_logit_logistic, TT_FORK, NULL, NULL },
+ { "log_logistic", test_log_logistic, TT_FORK, NULL, NULL },
+ { "weibull", test_weibull, TT_FORK, NULL, NULL },
+ { "genpareto", test_genpareto, TT_FORK, NULL, NULL },
+ { "uniform_interval", test_uniform_interval, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
+struct testcase_t slow_stochastic_prob_distr_tests[] = {
+ { "stochastic_genpareto", test_stochastic_genpareto, TT_FORK, NULL, NULL },
+ { "stochastic_geometric", test_stochastic_geometric, TT_FORK, NULL, NULL },
+ { "stochastic_uniform", test_stochastic_uniform, TT_FORK, NULL, NULL },
+ { "stochastic_logistic", test_stochastic_logistic, TT_FORK, NULL, NULL },
+ { "stochastic_log_logistic", test_stochastic_log_logistic, TT_FORK, NULL,
+ NULL },
+ { "stochastic_weibull", test_stochastic_weibull, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_process.c b/src/test/test_process.c
new file mode 100644
index 0000000000..b5185242d3
--- /dev/null
+++ b/src/test/test_process.c
@@ -0,0 +1,669 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_process.c
+ * \brief Test cases for the Process API.
+ */
+
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "test/test.h"
+#include "lib/process/env.h"
+
+#define PROCESS_PRIVATE
+#include "lib/process/process.h"
+#define PROCESS_UNIX_PRIVATE
+#include "lib/process/process_unix.h"
+#define PROCESS_WIN32_PRIVATE
+#include "lib/process/process_win32.h"
+
+static const char *stdout_read_buffer;
+static const char *stderr_read_buffer;
+
+struct process_data_t {
+ smartlist_t *stdout_data;
+ smartlist_t *stderr_data;
+ smartlist_t *stdin_data;
+ process_exit_code_t exit_code;
+};
+
+typedef struct process_data_t process_data_t;
+
+static process_data_t *
+process_data_new(void)
+{
+ process_data_t *process_data = tor_malloc_zero(sizeof(process_data_t));
+ process_data->stdout_data = smartlist_new();
+ process_data->stderr_data = smartlist_new();
+ process_data->stdin_data = smartlist_new();
+ return process_data;
+}
+
+static void
+process_data_free(process_data_t *process_data)
+{
+ if (process_data == NULL)
+ return;
+
+ SMARTLIST_FOREACH(process_data->stdout_data, char *, x, tor_free(x));
+ SMARTLIST_FOREACH(process_data->stderr_data, char *, x, tor_free(x));
+ SMARTLIST_FOREACH(process_data->stdin_data, char *, x, tor_free(x));
+
+ smartlist_free(process_data->stdout_data);
+ smartlist_free(process_data->stderr_data);
+ smartlist_free(process_data->stdin_data);
+ tor_free(process_data);
+}
+
+static int
+process_mocked_read_stdout(process_t *process, buf_t *buffer)
+{
+ (void)process;
+
+ if (stdout_read_buffer != NULL) {
+ buf_add_string(buffer, stdout_read_buffer);
+ stdout_read_buffer = NULL;
+ }
+
+ return (int)buf_datalen(buffer);
+}
+
+static int
+process_mocked_read_stderr(process_t *process, buf_t *buffer)
+{
+ (void)process;
+
+ if (stderr_read_buffer != NULL) {
+ buf_add_string(buffer, stderr_read_buffer);
+ stderr_read_buffer = NULL;
+ }
+
+ return (int)buf_datalen(buffer);
+}
+
+static void
+process_mocked_write_stdin(process_t *process, buf_t *buffer)
+{
+ const size_t size = buf_datalen(buffer);
+
+ if (size == 0)
+ return;
+
+ char *data = tor_malloc_zero(size + 1);
+ process_data_t *process_data = process_get_data(process);
+
+ buf_get_bytes(buffer, data, size);
+ smartlist_add(process_data->stdin_data, data);
+}
+
+static void
+process_stdout_callback(process_t *process, const char *data, size_t size)
+{
+ tt_ptr_op(process, OP_NE, NULL);
+ tt_ptr_op(data, OP_NE, NULL);
+ tt_int_op(strlen(data), OP_EQ, size);
+
+ process_data_t *process_data = process_get_data(process);
+ smartlist_add(process_data->stdout_data, tor_strdup(data));
+
+ done:
+ return;
+}
+
+static void
+process_stderr_callback(process_t *process, const char *data, size_t size)
+{
+ tt_ptr_op(process, OP_NE, NULL);
+ tt_ptr_op(data, OP_NE, NULL);
+ tt_int_op(strlen(data), OP_EQ, size);
+
+ process_data_t *process_data = process_get_data(process);
+ smartlist_add(process_data->stderr_data, tor_strdup(data));
+
+ done:
+ return;
+}
+
+static bool
+process_exit_callback(process_t *process, process_exit_code_t exit_code)
+{
+ tt_ptr_op(process, OP_NE, NULL);
+
+ process_data_t *process_data = process_get_data(process);
+ process_data->exit_code = exit_code;
+
+ done:
+ /* Do not free up our process_t. */
+ return false;
+}
+
+static void
+test_default_values(void *arg)
+{
+ (void)arg;
+ process_t *process = process_new("/path/to/nothing");
+
+ /* We are not running by default. */
+ tt_int_op(PROCESS_STATUS_NOT_RUNNING, OP_EQ, process_get_status(process));
+
+ /* We use the line protocol by default. */
+ tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process));
+
+ /* We don't set any custom data by default. */
+ tt_ptr_op(NULL, OP_EQ, process_get_data(process));
+
+ /* Our command was given to the process_t's constructor in process_new(). */
+ tt_str_op("/path/to/nothing", OP_EQ, process_get_command(process));
+
+ /* Make sure we are listed in the list of processes. */
+ tt_assert(smartlist_contains(process_get_all_processes(),
+ process));
+
+ /* Default PID is 0. */
+ tt_u64_op(0, OP_EQ, process_get_pid(process));
+
+ /* Our arguments should be empty. */
+ tt_int_op(0, OP_EQ,
+ smartlist_len(process_get_arguments(process)));
+
+ done:
+ process_free(process);
+}
+
+static void
+test_environment(void *arg)
+{
+ (void)arg;
+
+ process_t *process = process_new("");
+ process_environment_t *env = NULL;
+
+ process_set_environment(process, "E", "F");
+ process_set_environment(process, "C", "D");
+ process_set_environment(process, "A", "B");
+
+ env = process_get_environment(process);
+ tt_mem_op(env->windows_environment_block, OP_EQ,
+ "A=B\0C=D\0E=F\0", 12);
+ tt_str_op(env->unixoid_environment_block[0], OP_EQ,
+ "A=B");
+ tt_str_op(env->unixoid_environment_block[1], OP_EQ,
+ "C=D");
+ tt_str_op(env->unixoid_environment_block[2], OP_EQ,
+ "E=F");
+ tt_ptr_op(env->unixoid_environment_block[3], OP_EQ,
+ NULL);
+ process_environment_free(env);
+
+ /* Reset our environment. */
+ smartlist_t *new_env = smartlist_new();
+ smartlist_add(new_env, (char *)"FOO=bar");
+ smartlist_add(new_env, (char *)"HELLO=world");
+
+ process_reset_environment(process, new_env);
+ smartlist_free(new_env);
+
+ env = process_get_environment(process);
+ tt_mem_op(env->windows_environment_block, OP_EQ,
+ "FOO=bar\0HELLO=world\0", 20);
+ tt_str_op(env->unixoid_environment_block[0], OP_EQ,
+ "FOO=bar");
+ tt_str_op(env->unixoid_environment_block[1], OP_EQ,
+ "HELLO=world");
+ tt_ptr_op(env->unixoid_environment_block[2], OP_EQ,
+ NULL);
+
+ done:
+ process_environment_free(env);
+ process_free(process);
+}
+
+static void
+test_stringified_types(void *arg)
+{
+ (void)arg;
+
+ /* process_protocol_t values. */
+ tt_str_op("Raw", OP_EQ, process_protocol_to_string(PROCESS_PROTOCOL_RAW));
+ tt_str_op("Line", OP_EQ, process_protocol_to_string(PROCESS_PROTOCOL_LINE));
+
+ /* process_status_t values. */
+ tt_str_op("not running", OP_EQ,
+ process_status_to_string(PROCESS_STATUS_NOT_RUNNING));
+ tt_str_op("running", OP_EQ,
+ process_status_to_string(PROCESS_STATUS_RUNNING));
+ tt_str_op("error", OP_EQ,
+ process_status_to_string(PROCESS_STATUS_ERROR));
+
+ done:
+ return;
+}
+
+static void
+test_line_protocol_simple(void *arg)
+{
+ (void)arg;
+
+ process_data_t *process_data = process_data_new();
+
+ process_t *process = process_new("");
+ process_set_data(process, process_data);
+
+ process_set_stdout_read_callback(process, process_stdout_callback);
+ process_set_stderr_read_callback(process, process_stderr_callback);
+
+ MOCK(process_read_stdout, process_mocked_read_stdout);
+ MOCK(process_read_stderr, process_mocked_read_stderr);
+
+ /* Make sure we are running with the line protocol. */
+ tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process));
+
+ tt_int_op(0, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(0, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ stdout_read_buffer = "Hello stdout\n";
+ process_notify_event_stdout(process);
+ tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
+
+ stderr_read_buffer = "Hello stderr\r\n";
+ process_notify_event_stderr(process);
+ tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
+
+ /* Data should be ready. */
+ tt_int_op(1, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(1, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ /* Check if the data is correct. */
+ tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ,
+ "Hello stdout");
+ tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ,
+ "Hello stderr");
+
+ done:
+ process_data_free(process_data);
+ process_free(process);
+
+ UNMOCK(process_read_stdout);
+ UNMOCK(process_read_stderr);
+}
+
+static void
+test_line_protocol_multi(void *arg)
+{
+ (void)arg;
+
+ process_data_t *process_data = process_data_new();
+
+ process_t *process = process_new("");
+ process_set_data(process, process_data);
+ process_set_stdout_read_callback(process, process_stdout_callback);
+ process_set_stderr_read_callback(process, process_stderr_callback);
+
+ MOCK(process_read_stdout, process_mocked_read_stdout);
+ MOCK(process_read_stderr, process_mocked_read_stderr);
+
+ /* Make sure we are running with the line protocol. */
+ tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process));
+
+ tt_int_op(0, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(0, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ stdout_read_buffer = "Hello stdout\r\nOnion Onion Onion\nA B C D\r\n\r\n";
+ process_notify_event_stdout(process);
+ tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
+
+ stderr_read_buffer = "Hello stderr\nFoo bar baz\nOnion Onion Onion\n";
+ process_notify_event_stderr(process);
+ tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
+
+ /* Data should be ready. */
+ tt_int_op(4, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(3, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ /* Check if the data is correct. */
+ tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ,
+ "Hello stdout");
+ tt_str_op(smartlist_get(process_data->stdout_data, 1), OP_EQ,
+ "Onion Onion Onion");
+ tt_str_op(smartlist_get(process_data->stdout_data, 2), OP_EQ,
+ "A B C D");
+ tt_str_op(smartlist_get(process_data->stdout_data, 3), OP_EQ,
+ "");
+
+ tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ,
+ "Hello stderr");
+ tt_str_op(smartlist_get(process_data->stderr_data, 1), OP_EQ,
+ "Foo bar baz");
+ tt_str_op(smartlist_get(process_data->stderr_data, 2), OP_EQ,
+ "Onion Onion Onion");
+
+ done:
+ process_data_free(process_data);
+ process_free(process);
+
+ UNMOCK(process_read_stdout);
+ UNMOCK(process_read_stderr);
+}
+
+static void
+test_line_protocol_partial(void *arg)
+{
+ (void)arg;
+
+ process_data_t *process_data = process_data_new();
+
+ process_t *process = process_new("");
+ process_set_data(process, process_data);
+ process_set_stdout_read_callback(process, process_stdout_callback);
+ process_set_stderr_read_callback(process, process_stderr_callback);
+
+ MOCK(process_read_stdout, process_mocked_read_stdout);
+ MOCK(process_read_stderr, process_mocked_read_stderr);
+
+ /* Make sure we are running with the line protocol. */
+ tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process));
+
+ tt_int_op(0, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(0, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ stdout_read_buffer = "Hello stdout this is a partial line ...";
+ process_notify_event_stdout(process);
+ tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
+
+ stderr_read_buffer = "Hello stderr this is a partial line ...";
+ process_notify_event_stderr(process);
+ tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
+
+ /* Data should NOT be ready. */
+ tt_int_op(0, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(0, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ stdout_read_buffer = " the end\nAnother partial string goes here ...";
+ process_notify_event_stdout(process);
+ tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
+
+ stderr_read_buffer = " the end\nAnother partial string goes here ...";
+ process_notify_event_stderr(process);
+ tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
+
+ /* Some data should be ready. */
+ tt_int_op(1, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(1, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ stdout_read_buffer = " the end\nFoo bar baz\n";
+ process_notify_event_stdout(process);
+ tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
+
+ stderr_read_buffer = " the end\nFoo bar baz\n";
+ process_notify_event_stderr(process);
+ tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
+
+ /* Some data should be ready. */
+ tt_int_op(3, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(3, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ /* Check if the data is correct. */
+ tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ,
+ "Hello stdout this is a partial line ... the end");
+ tt_str_op(smartlist_get(process_data->stdout_data, 1), OP_EQ,
+ "Another partial string goes here ... the end");
+ tt_str_op(smartlist_get(process_data->stdout_data, 2), OP_EQ,
+ "Foo bar baz");
+
+ tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ,
+ "Hello stderr this is a partial line ... the end");
+ tt_str_op(smartlist_get(process_data->stderr_data, 1), OP_EQ,
+ "Another partial string goes here ... the end");
+ tt_str_op(smartlist_get(process_data->stderr_data, 2), OP_EQ,
+ "Foo bar baz");
+
+ done:
+ process_data_free(process_data);
+ process_free(process);
+
+ UNMOCK(process_read_stdout);
+ UNMOCK(process_read_stderr);
+}
+
+static void
+test_raw_protocol_simple(void *arg)
+{
+ (void)arg;
+
+ process_data_t *process_data = process_data_new();
+
+ process_t *process = process_new("");
+ process_set_data(process, process_data);
+ process_set_protocol(process, PROCESS_PROTOCOL_RAW);
+
+ process_set_stdout_read_callback(process, process_stdout_callback);
+ process_set_stderr_read_callback(process, process_stderr_callback);
+
+ MOCK(process_read_stdout, process_mocked_read_stdout);
+ MOCK(process_read_stderr, process_mocked_read_stderr);
+
+ /* Make sure we are running with the raw protocol. */
+ tt_int_op(PROCESS_PROTOCOL_RAW, OP_EQ, process_get_protocol(process));
+
+ tt_int_op(0, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(0, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ stdout_read_buffer = "Hello stdout\n";
+ process_notify_event_stdout(process);
+ tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
+
+ stderr_read_buffer = "Hello stderr\n";
+ process_notify_event_stderr(process);
+ tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
+
+ /* Data should be ready. */
+ tt_int_op(1, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(1, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ stdout_read_buffer = "Hello, again, stdout\nThis contains multiple lines";
+ process_notify_event_stdout(process);
+ tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
+
+ stderr_read_buffer = "Hello, again, stderr\nThis contains multiple lines";
+ process_notify_event_stderr(process);
+ tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
+
+ /* Data should be ready. */
+ tt_int_op(2, OP_EQ, smartlist_len(process_data->stdout_data));
+ tt_int_op(2, OP_EQ, smartlist_len(process_data->stderr_data));
+
+ /* Check if the data is correct. */
+ tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ,
+ "Hello stdout\n");
+ tt_str_op(smartlist_get(process_data->stdout_data, 1), OP_EQ,
+ "Hello, again, stdout\nThis contains multiple lines");
+
+ tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ,
+ "Hello stderr\n");
+ tt_str_op(smartlist_get(process_data->stderr_data, 1), OP_EQ,
+ "Hello, again, stderr\nThis contains multiple lines");
+
+ done:
+ process_data_free(process_data);
+ process_free(process);
+
+ UNMOCK(process_read_stdout);
+ UNMOCK(process_read_stderr);
+}
+
+static void
+test_write_simple(void *arg)
+{
+ (void)arg;
+
+ process_data_t *process_data = process_data_new();
+
+ process_t *process = process_new("");
+ process_set_data(process, process_data);
+
+ MOCK(process_write_stdin, process_mocked_write_stdin);
+
+ process_write(process, (uint8_t *)"Hello world\n", 12);
+ process_notify_event_stdin(process);
+ tt_int_op(1, OP_EQ, smartlist_len(process_data->stdin_data));
+
+ process_printf(process, "Hello %s !\n", "moon");
+ process_notify_event_stdin(process);
+ tt_int_op(2, OP_EQ, smartlist_len(process_data->stdin_data));
+
+ done:
+ process_data_free(process_data);
+ process_free(process);
+
+ UNMOCK(process_write_stdin);
+}
+
+static void
+test_exit_simple(void *arg)
+{
+ (void)arg;
+
+ process_data_t *process_data = process_data_new();
+
+ process_t *process = process_new("");
+ process_set_data(process, process_data);
+ process_set_exit_callback(process, process_exit_callback);
+
+ /* Our default is 0. */
+ tt_u64_op(0, OP_EQ, process_data->exit_code);
+
+ /* Fake that we are a running process. */
+ process_set_status(process, PROCESS_STATUS_RUNNING);
+ tt_int_op(process_get_status(process), OP_EQ, PROCESS_STATUS_RUNNING);
+
+ /* Fake an exit. */
+ process_notify_event_exit(process, 1337);
+
+ /* Check if our state changed and if our callback fired. */
+ tt_int_op(process_get_status(process), OP_EQ, PROCESS_STATUS_NOT_RUNNING);
+ tt_u64_op(1337, OP_EQ, process_data->exit_code);
+
+ done:
+ process_set_data(process, process_data);
+ process_data_free(process_data);
+ process_free(process);
+}
+
+static void
+test_argv_simple(void *arg)
+{
+ (void)arg;
+
+ process_t *process = process_new("/bin/cat");
+ char **argv = NULL;
+
+ /* Setup some arguments. */
+ process_append_argument(process, "foo");
+ process_append_argument(process, "bar");
+ process_append_argument(process, "baz");
+
+ /* Check the number of elements. */
+ tt_int_op(3, OP_EQ,
+ smartlist_len(process_get_arguments(process)));
+
+ /* Let's try to convert it into a Unix style char **argv. */
+ argv = process_get_argv(process);
+
+ /* Check our values. */
+ tt_str_op(argv[0], OP_EQ, "/bin/cat");
+ tt_str_op(argv[1], OP_EQ, "foo");
+ tt_str_op(argv[2], OP_EQ, "bar");
+ tt_str_op(argv[3], OP_EQ, "baz");
+ tt_ptr_op(argv[4], OP_EQ, NULL);
+
+ done:
+ tor_free(argv);
+ process_free(process);
+}
+
+static void
+test_unix(void *arg)
+{
+ (void)arg;
+#ifndef _WIN32
+ process_t *process = process_new("");
+
+ /* On Unix all processes should have a Unix process handle. */
+ tt_ptr_op(NULL, OP_NE, process_get_unix_process(process));
+
+ done:
+ process_free(process);
+#endif /* !defined(_WIN32) */
+}
+
+static void
+test_win32(void *arg)
+{
+ (void)arg;
+#ifdef _WIN32
+ process_t *process = process_new("");
+ char *joined_argv = NULL;
+
+ /* On Win32 all processes should have a Win32 process handle. */
+ tt_ptr_op(NULL, OP_NE, process_get_win32_process(process));
+
+ /* Based on some test cases from "Parsing C++ Command-Line Arguments" in
+ * MSDN but we don't exercise all quoting rules because tor_join_win_cmdline
+ * will try to only generate simple cases for the child process to parse;
+ * i.e. we never embed quoted strings in arguments. */
+
+ const char *argvs[][4] = {
+ {"a", "bb", "CCC", NULL}, // Normal
+ {NULL, NULL, NULL, NULL}, // Empty argument list
+ {"", NULL, NULL, NULL}, // Empty argument
+ {"\"a", "b\"b", "CCC\"", NULL}, // Quotes
+ {"a\tbc", "dd dd", "E", NULL}, // Whitespace
+ {"a\\\\\\b", "de fg", "H", NULL}, // Backslashes
+ {"a\\\"b", "\\c", "D\\", NULL}, // Backslashes before quote
+ {"a\\\\b c", "d", "E", NULL}, // Backslashes not before quote
+ { NULL } // Terminator
+ };
+
+ const char *cmdlines[] = {
+ "a bb CCC",
+ "",
+ "\"\"",
+ "\\\"a b\\\"b CCC\\\"",
+ "\"a\tbc\" \"dd dd\" E",
+ "a\\\\\\b \"de fg\" H",
+ "a\\\\\\\"b \\c D\\",
+ "\"a\\\\b c\" d E",
+ NULL // Terminator
+ };
+
+ int i;
+
+ for (i=0; cmdlines[i]!=NULL; i++) {
+ log_info(LD_GENERAL, "Joining argvs[%d], expecting <%s>", i, cmdlines[i]);
+ joined_argv = tor_join_win_cmdline(argvs[i]);
+ tt_str_op(cmdlines[i],OP_EQ, joined_argv);
+ tor_free(joined_argv);
+ }
+
+ done:
+ tor_free(joined_argv);
+ process_free(process);
+#endif /* defined(_WIN32) */
+}
+
+struct testcase_t process_tests[] = {
+ { "default_values", test_default_values, TT_FORK, NULL, NULL },
+ { "environment", test_environment, TT_FORK, NULL, NULL },
+ { "stringified_types", test_stringified_types, TT_FORK, NULL, NULL },
+ { "line_protocol_simple", test_line_protocol_simple, TT_FORK, NULL, NULL },
+ { "line_protocol_multi", test_line_protocol_multi, TT_FORK, NULL, NULL },
+ { "line_protocol_partial", test_line_protocol_partial, TT_FORK, NULL, NULL },
+ { "raw_protocol_simple", test_raw_protocol_simple, TT_FORK, NULL, NULL },
+ { "write_simple", test_write_simple, TT_FORK, NULL, NULL },
+ { "exit_simple", test_exit_simple, TT_FORK, NULL, NULL },
+ { "argv_simple", test_argv_simple, TT_FORK, NULL, NULL },
+ { "unix", test_unix, TT_FORK, NULL, NULL },
+ { "win32", test_win32, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_process_descs.c b/src/test/test_process_descs.c
new file mode 100644
index 0000000000..5c2301f873
--- /dev/null
+++ b/src/test/test_process_descs.c
@@ -0,0 +1,70 @@
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#include "core/or/or.h"
+#include "feature/dirauth/process_descs.h"
+
+#include "test/test.h"
+
+static void
+test_process_descs_versions(void *arg)
+{
+ (void)arg;
+ struct {
+ const char *version;
+ bool should_reject;
+ } cases[] = {
+ // a very old version: reject.
+ { "Tor 0.1.2.3-alpha", true },
+ // a non-tor program: don't reject.
+ { "Wombat 0.1.2.3-alpha", false },
+ // some unsupported versions: reject.
+ { "Tor 0.2.9.4-alpha", true },
+ { "Tor 0.2.9.5-alpha", true },
+ { "Tor 0.2.9.100", true },
+ { "Tor 0.3.0.0-alpha-dev", true },
+ { "Tor 0.3.0.2-alpha", true },
+ { "Tor 0.3.0.5", true },
+ { "Tor 0.3.1.4", true },
+ { "Tor 0.3.2.4", true },
+ { "Tor 0.3.3.4", true },
+ { "Tor 0.3.4.1-alpha", true },
+ { "Tor 0.3.4.100", true },
+ { "Tor 0.3.5.1-alpha", true },
+ { "Tor 0.3.5.6-rc", true},
+ { "Tor 0.4.0.1-alpha", true },
+ { "Tor 0.4.0.5", true },
+ { "Tor 0.4.1.1-alpha", true },
+ { "Tor 0.4.1.4-rc", true },
+ { "Tor 0.4.1.5", true },
+ // new enough to be supported
+ { "Tor 0.3.5.7", false },
+ { "Tor 0.3.5.8", false },
+ { "Tor 0.4.2.1-alpha", false },
+ { "Tor 0.4.2.4-rc", false },
+ { "Tor 0.4.3.0-alpha-dev", false },
+ // Very far in the future
+ { "Tor 100.100.1.5", false },
+ };
+ size_t n_cases = ARRAY_LENGTH(cases);
+
+ for (unsigned i = 0; i < n_cases; ++i) {
+ const char *msg = NULL;
+ bool rejected = dirserv_rejects_tor_version(cases[i].version, &msg);
+ tt_int_op(rejected, OP_EQ, cases[i].should_reject);
+ tt_int_op(msg == NULL, OP_EQ, rejected == false);
+ }
+
+ done:
+ ;
+}
+
+#define T(name,flags) \
+ { #name, test_process_descs_##name, (flags), NULL, NULL }
+
+struct testcase_t process_descs_tests[] = {
+ T(versions,0),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_process_slow.c b/src/test/test_process_slow.c
new file mode 100644
index 0000000000..f74d4adc9a
--- /dev/null
+++ b/src/test/test_process_slow.c
@@ -0,0 +1,365 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_process_slow.c
+ * \brief Slow test cases for the Process API.
+ */
+
+#define MAINLOOP_PRIVATE
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "core/mainloop/mainloop.h"
+#include "lib/evloop/compat_libevent.h"
+#include "lib/process/process.h"
+#include "lib/process/waitpid.h"
+#include "test/test.h"
+
+#ifndef BUILDDIR
+#define BUILDDIR "."
+#endif
+
+#ifdef _WIN32
+#define TEST_PROCESS "test-process.exe"
+#else
+#define TEST_PROCESS BUILDDIR "/src/test/test-process"
+#endif /* defined(_WIN32) */
+
+/** Timer that ticks once a second and stop the event loop after 5 ticks. */
+static periodic_timer_t *main_loop_timeout_timer;
+
+/** How many times have our timer ticked? */
+static int timer_tick_count;
+
+struct process_data_t {
+ smartlist_t *stdout_data;
+ smartlist_t *stderr_data;
+ smartlist_t *stdin_data;
+ process_exit_code_t exit_code;
+ bool did_exit;
+};
+
+typedef struct process_data_t process_data_t;
+
+static process_data_t *
+process_data_new(void)
+{
+ process_data_t *process_data = tor_malloc_zero(sizeof(process_data_t));
+ process_data->stdout_data = smartlist_new();
+ process_data->stderr_data = smartlist_new();
+ process_data->stdin_data = smartlist_new();
+ return process_data;
+}
+
+static void
+process_data_free(process_data_t *process_data)
+{
+ if (process_data == NULL)
+ return;
+
+ SMARTLIST_FOREACH(process_data->stdout_data, char *, x, tor_free(x));
+ SMARTLIST_FOREACH(process_data->stderr_data, char *, x, tor_free(x));
+ SMARTLIST_FOREACH(process_data->stdin_data, char *, x, tor_free(x));
+
+ smartlist_free(process_data->stdout_data);
+ smartlist_free(process_data->stderr_data);
+ smartlist_free(process_data->stdin_data);
+ tor_free(process_data);
+}
+
+static void
+process_stdout_callback(process_t *process, const char *data, size_t size)
+{
+ tt_ptr_op(process, OP_NE, NULL);
+ tt_ptr_op(data, OP_NE, NULL);
+ tt_int_op(strlen(data), OP_EQ, size);
+
+ process_data_t *process_data = process_get_data(process);
+ smartlist_add(process_data->stdout_data, tor_strdup(data));
+
+ done:
+ return;
+}
+
+static void
+process_stderr_callback(process_t *process, const char *data, size_t size)
+{
+ tt_ptr_op(process, OP_NE, NULL);
+ tt_ptr_op(data, OP_NE, NULL);
+ tt_int_op(strlen(data), OP_EQ, size);
+
+ process_data_t *process_data = process_get_data(process);
+ smartlist_add(process_data->stderr_data, tor_strdup(data));
+
+ done:
+ return;
+}
+
+static bool
+process_exit_callback(process_t *process, process_exit_code_t exit_code)
+{
+ process_status_t status;
+
+ tt_ptr_op(process, OP_NE, NULL);
+
+ process_data_t *process_data = process_get_data(process);
+ process_data->exit_code = exit_code;
+ process_data->did_exit = true;
+
+ /* Check if our process is still running? */
+ status = process_get_status(process);
+ tt_int_op(status, OP_EQ, PROCESS_STATUS_NOT_RUNNING);
+
+ done:
+ /* Do not free up our process_t. */
+ return false;
+}
+
+#ifdef _WIN32
+static const char *
+get_win32_test_binary_path(void)
+{
+ static char buffer[MAX_PATH];
+
+ /* Get the absolute path of our binary: \path\to\test-slow.exe. */
+ GetModuleFileNameA(GetModuleHandle(0), buffer, sizeof(buffer));
+
+ /* Find our process name. */
+ char *offset = strstr(buffer, "test-slow.exe");
+ tt_ptr_op(offset, OP_NE, NULL);
+
+ /* Change test-slow.exe to test-process.exe. */
+ memcpy(offset, TEST_PROCESS, strlen(TEST_PROCESS));
+
+ return buffer;
+ done:
+ return NULL;
+}
+#endif /* defined(_WIN32) */
+
+static void
+main_loop_timeout_cb(periodic_timer_t *timer, void *data)
+{
+ /* Sanity check. */
+ tt_ptr_op(timer, OP_EQ, main_loop_timeout_timer);
+ tt_ptr_op(data, OP_NE, NULL);
+
+ /* Our process data. */
+ process_data_t *process_data = data;
+
+ /* Our process did exit. */
+ if (process_data->did_exit)
+ tor_shutdown_event_loop_and_exit(0);
+
+ /* Have we been called 10 times we exit the main loop. */
+ timer_tick_count++;
+
+ tt_int_op(timer_tick_count, OP_LT, 10);
+
+#ifndef _WIN32
+ /* Call waitpid callbacks. */
+ notify_pending_waitpid_callbacks();
+#endif
+
+ return;
+ done:
+ /* Exit with an error. */
+ tor_shutdown_event_loop_and_exit(-1);
+}
+
+static void
+run_main_loop(process_data_t *process_data)
+{
+ int ret;
+
+ /* Wake up after 1 seconds. */
+ static const struct timeval interval = {1, 0};
+
+ timer_tick_count = 0;
+ main_loop_timeout_timer = periodic_timer_new(tor_libevent_get_base(),
+ &interval,
+ main_loop_timeout_cb,
+ process_data);
+
+ /* Run our main loop. */
+ ret = run_main_loop_until_done();
+
+ /* Clean up our main loop timeout timer. */
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ periodic_timer_free(main_loop_timeout_timer);
+}
+
+static void
+test_callbacks(void *arg)
+{
+ (void)arg;
+ const char *filename = NULL;
+
+#ifdef _WIN32
+ filename = get_win32_test_binary_path();
+#else
+ filename = TEST_PROCESS;
+#endif
+
+ /* Process callback data. */
+ process_data_t *process_data = process_data_new();
+
+ /* Setup our process. */
+ process_t *process = process_new(filename);
+ process_set_data(process, process_data);
+ process_set_stdout_read_callback(process, process_stdout_callback);
+ process_set_stderr_read_callback(process, process_stderr_callback);
+ process_set_exit_callback(process, process_exit_callback);
+
+ /* Set environment variable. */
+ process_set_environment(process, "TOR_TEST_ENV", "Hello, from Tor!");
+
+ /* Add some arguments. */
+ process_append_argument(process, "This is the first one");
+ process_append_argument(process, "Second one");
+ process_append_argument(process, "Third: Foo bar baz");
+
+ /* Run our process. */
+ process_status_t status;
+
+ status = process_exec(process);
+ tt_int_op(status, OP_EQ, PROCESS_STATUS_RUNNING);
+
+ /* Write some lines to stdin. */
+ process_printf(process, "Hi process!\r\n");
+ process_printf(process, "Can you read more than one line?\n");
+ process_printf(process, "Can you read partial ...");
+ process_printf(process, " lines?\r\n");
+
+ /* Start our main loop. */
+ run_main_loop(process_data);
+
+ /* We returned. Let's see what our event loop said. */
+ tt_int_op(smartlist_len(process_data->stdout_data), OP_EQ, 12);
+ tt_int_op(smartlist_len(process_data->stderr_data), OP_EQ, 3);
+ tt_assert(process_data->did_exit);
+ tt_u64_op(process_data->exit_code, OP_EQ, 0);
+
+ /* Check stdout output. */
+ char argv0_expected[256];
+ tor_snprintf(argv0_expected, sizeof(argv0_expected),
+ "argv[0] = '%s'", filename);
+
+ tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ,
+ argv0_expected);
+ tt_str_op(smartlist_get(process_data->stdout_data, 1), OP_EQ,
+ "argv[1] = 'This is the first one'");
+ tt_str_op(smartlist_get(process_data->stdout_data, 2), OP_EQ,
+ "argv[2] = 'Second one'");
+ tt_str_op(smartlist_get(process_data->stdout_data, 3), OP_EQ,
+ "argv[3] = 'Third: Foo bar baz'");
+ tt_str_op(smartlist_get(process_data->stdout_data, 4), OP_EQ,
+ "Environment variable TOR_TEST_ENV = 'Hello, from Tor!'");
+ tt_str_op(smartlist_get(process_data->stdout_data, 5), OP_EQ,
+ "Output on stdout");
+ tt_str_op(smartlist_get(process_data->stdout_data, 6), OP_EQ,
+ "This is a new line");
+ tt_str_op(smartlist_get(process_data->stdout_data, 7), OP_EQ,
+ "Partial line on stdout ...end of partial line on stdout");
+ tt_str_op(smartlist_get(process_data->stdout_data, 8), OP_EQ,
+ "Read line from stdin: 'Hi process!'");
+ tt_str_op(smartlist_get(process_data->stdout_data, 9), OP_EQ,
+ "Read line from stdin: 'Can you read more than one line?'");
+ tt_str_op(smartlist_get(process_data->stdout_data, 10), OP_EQ,
+ "Read line from stdin: 'Can you read partial ... lines?'");
+ tt_str_op(smartlist_get(process_data->stdout_data, 11), OP_EQ,
+ "We are done for here, thank you!");
+
+ /* Check stderr output. */
+ tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ,
+ "Output on stderr");
+ tt_str_op(smartlist_get(process_data->stderr_data, 1), OP_EQ,
+ "This is a new line");
+ tt_str_op(smartlist_get(process_data->stderr_data, 2), OP_EQ,
+ "Partial line on stderr ...end of partial line on stderr");
+
+ done:
+ process_data_free(process_data);
+ process_free(process);
+}
+
+static void
+test_callbacks_terminate(void *arg)
+{
+ (void)arg;
+ const char *filename = NULL;
+
+#ifdef _WIN32
+ filename = get_win32_test_binary_path();
+#else
+ filename = TEST_PROCESS;
+#endif
+
+ /* Process callback data. */
+ process_data_t *process_data = process_data_new();
+
+ /* Setup our process. */
+ process_t *process = process_new(filename);
+ process_set_data(process, process_data);
+ process_set_exit_callback(process, process_exit_callback);
+
+ /* Run our process. */
+ process_status_t status;
+
+ status = process_exec(process);
+ tt_int_op(status, OP_EQ, PROCESS_STATUS_RUNNING);
+
+ /* Zap our process. */
+ bool success;
+
+ success = process_terminate(process);
+ tt_assert(success);
+
+ /* Start our main loop. */
+ run_main_loop(process_data);
+
+ /* Check if we did exit. */
+ tt_assert(process_data->did_exit);
+
+ done:
+ process_data_free(process_data);
+ process_free(process);
+}
+
+static void
+test_nonexistent_executable(void *arg)
+{
+ (void)arg;
+
+ /* Process callback data. */
+ process_data_t *process_data = process_data_new();
+
+ /* Setup our process. */
+ process_t *process = process_new("binary-does-not-exist");
+ process_set_data(process, process_data);
+ process_set_exit_callback(process, process_exit_callback);
+
+ /* Run our process. */
+ process_exec(process);
+
+ /* Start our main loop. */
+ run_main_loop(process_data);
+
+ /* Ensure that the exit callback was actually called even though the binary
+ * did not exist.
+ */
+ tt_assert(process_data->did_exit);
+
+ done:
+ process_data_free(process_data);
+ process_free(process);
+}
+
+struct testcase_t slow_process_tests[] = {
+ { "callbacks", test_callbacks, 0, NULL, NULL },
+ { "callbacks_terminate", test_callbacks_terminate, 0, NULL, NULL },
+ { "nonexistent_executable", test_nonexistent_executable, 0, NULL, NULL },
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_procmon.c b/src/test/test_procmon.c
index e23578f4fd..1752008f63 100644
--- a/src/test/test_procmon.c
+++ b/src/test/test_procmon.c
@@ -1,7 +1,6 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define PROCMON_PRIVATE
#include "orconfig.h"
#include "core/or/or.h"
#include "test/test.h"
@@ -10,8 +9,6 @@
#include "test/log_test_helpers.h"
-#define NS_MODULE procmon
-
struct event_base;
static void
diff --git a/src/test/test_proto_haproxy.c b/src/test/test_proto_haproxy.c
new file mode 100644
index 0000000000..040354ec1f
--- /dev/null
+++ b/src/test/test_proto_haproxy.c
@@ -0,0 +1,66 @@
+/* Copyright (c) 2019-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_proto_haproxy.c
+ * \brief Tests for our HAProxy protocol parser code
+ */
+
+#define PROTO_HAPROXY_PRIVATE
+
+#include "test/test.h"
+#include "core/proto/proto_haproxy.h"
+#include "test/log_test_helpers.h"
+
+static void
+test_format_proxy_header_line(void *arg)
+{
+ tor_addr_t addr;
+ tor_addr_port_t *addr_port = NULL;
+ char *output = NULL;
+
+ (void) arg;
+
+ /* IPv4 address. */
+ tor_addr_parse(&addr, "192.168.1.2");
+ addr_port = tor_addr_port_new(&addr, 8000);
+ output = haproxy_format_proxy_header_line(addr_port);
+
+ tt_str_op(output, OP_EQ, "PROXY TCP4 0.0.0.0 192.168.1.2 0 8000\r\n");
+
+ tor_free(addr_port);
+ tor_free(output);
+
+ /* IPv6 address. */
+ tor_addr_parse(&addr, "123:45:6789::5005:11");
+ addr_port = tor_addr_port_new(&addr, 8000);
+ output = haproxy_format_proxy_header_line(addr_port);
+
+ tt_str_op(output, OP_EQ, "PROXY TCP6 :: 123:45:6789::5005:11 0 8000\r\n");
+
+ tor_free(addr_port);
+ tor_free(output);
+
+ /* UNIX socket address. */
+ memset(&addr, 0, sizeof(addr));
+ addr.family = AF_UNIX;
+ addr_port = tor_addr_port_new(&addr, 8000);
+ output = haproxy_format_proxy_header_line(addr_port);
+
+ /* If it's not an IPv4 or IPv6 address, haproxy_format_proxy_header_line
+ * must return NULL. */
+ tt_ptr_op(output, OP_EQ, NULL);
+
+ tor_free(addr_port);
+ tor_free(output);
+
+ done:
+ tor_free(addr_port);
+ tor_free(output);
+}
+
+struct testcase_t proto_haproxy_tests[] = {
+ { "format_proxy_header_line", test_format_proxy_header_line, 0, NULL, NULL },
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_proto_http.c b/src/test/test_proto_http.c
index 08990c0b6a..481d78b2c1 100644
--- a/src/test/test_proto_http.c
+++ b/src/test/test_proto_http.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,7 +8,7 @@
#include "core/or/or.h"
#include "test/test.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "core/proto/proto_http.h"
#include "test/log_test_helpers.h"
diff --git a/src/test/test_proto_misc.c b/src/test/test_proto_misc.c
index af9cf7eee2..64bf5c4993 100644
--- a/src/test/test_proto_misc.c
+++ b/src/test/test_proto_misc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,7 +8,7 @@
#include "core/or/or.h"
#include "test/test.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "core/or/connection_or.h"
#include "feature/relay/ext_orport.h"
#include "core/proto/proto_cell.h"
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index 3fbfe3a682..16f0279871 100644
--- a/src/test/test_protover.c
+++ b/src/test/test_protover.c
@@ -1,16 +1,23 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define PROTOVER_PRIVATE
+#define DIRVOTE_PRIVATE
#include "orconfig.h"
#include "test/test.h"
-#include "core/or/protover.h"
+#include "lib/tls/tortls.h"
#include "core/or/or.h"
+
#include "core/or/connection_or.h"
-#include "lib/tls/tortls.h"
+#include "core/or/protover.h"
+#include "core/or/versions.h"
+
+#include "feature/dirauth/dirvote.h"
+
+#include "feature/relay/relay_handshake.h"
static void
test_protover_parse(void *arg)
@@ -22,7 +29,7 @@ test_protover_parse(void *arg)
tt_skip();
done:
;
-#else
+#else /* !defined(HAVE_RUST) */
char *re_encoded = NULL;
const char *orig = "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16";
@@ -32,60 +39,32 @@ test_protover_parse(void *arg)
tt_int_op(smartlist_len(elts), OP_EQ, 4);
const proto_entry_t *e;
- const proto_range_t *r;
e = smartlist_get(elts, 0);
tt_str_op(e->name, OP_EQ, "Foo");
- tt_int_op(smartlist_len(e->ranges), OP_EQ, 2);
- {
- r = smartlist_get(e->ranges, 0);
- tt_int_op(r->low, OP_EQ, 1);
- tt_int_op(r->high, OP_EQ, 1);
-
- r = smartlist_get(e->ranges, 1);
- tt_int_op(r->low, OP_EQ, 3);
- tt_int_op(r->high, OP_EQ, 3);
- }
+ tt_int_op(e->bitmask, OP_EQ, 0x0a);
e = smartlist_get(elts, 1);
tt_str_op(e->name, OP_EQ, "Bar");
- tt_int_op(smartlist_len(e->ranges), OP_EQ, 1);
- {
- r = smartlist_get(e->ranges, 0);
- tt_int_op(r->low, OP_EQ, 3);
- tt_int_op(r->high, OP_EQ, 3);
- }
+ tt_int_op(e->bitmask, OP_EQ, 0x08);
e = smartlist_get(elts, 2);
tt_str_op(e->name, OP_EQ, "Baz");
- tt_int_op(smartlist_len(e->ranges), OP_EQ, 0);
+ tt_int_op(e->bitmask, OP_EQ, 0x00);
e = smartlist_get(elts, 3);
tt_str_op(e->name, OP_EQ, "Quux");
- tt_int_op(smartlist_len(e->ranges), OP_EQ, 3);
- {
- r = smartlist_get(e->ranges, 0);
- tt_int_op(r->low, OP_EQ, 9);
- tt_int_op(r->high, OP_EQ, 12);
-
- r = smartlist_get(e->ranges, 1);
- tt_int_op(r->low, OP_EQ, 14);
- tt_int_op(r->high, OP_EQ, 14);
-
- r = smartlist_get(e->ranges, 2);
- tt_int_op(r->low, OP_EQ, 15);
- tt_int_op(r->high, OP_EQ, 16);
- }
+ tt_int_op(e->bitmask, OP_EQ, 0x1de00);
re_encoded = encode_protocol_list(elts);
tt_assert(re_encoded);
- tt_str_op(re_encoded, OP_EQ, orig);
+ tt_str_op(re_encoded, OP_EQ, "Foo=1,3 Bar=3 Baz= Quux=9-12,14-16");
done:
if (elts)
SMARTLIST_FOREACH(elts, proto_entry_t *, ent, proto_entry_free(ent));
smartlist_free(elts);
tor_free(re_encoded);
-#endif
+#endif /* defined(HAVE_RUST) */
}
static void
@@ -129,7 +108,7 @@ test_protover_parse_fail(void *arg)
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
tt_ptr_op(elts, OP_EQ, NULL);
-#endif
+#endif /* defined(HAVE_RUST) */
done:
;
}
@@ -271,6 +250,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 +262,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 +273,7 @@ test_protover_all_supported(void *arg)
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaa=1-65536", &msg));
tor_end_capture_bugs_();
-#endif
+#endif /* !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL) */
done:
tor_end_capture_bugs_();
@@ -361,23 +342,18 @@ test_protover_supports_version(void *arg)
* Hard-coded here, because they are not in the code, or not exposed in the
* headers. */
#define PROTOVER_LINKAUTH_V1 1
-#define PROTOVER_LINKAUTH_V3 3
-
+#define PROTOVER_LINKAUTH_V2 2
#define PROTOVER_RELAY_V1 1
-#define PROTOVER_RELAY_V2 2
-/* Highest supported HSv2 introduce protocol version.
- * Hard-coded here, because it does not appear anywhere in the code.
- * It's not clear if we actually support version 2, see #25068. */
-#define PROTOVER_HSINTRO_V2 4
+/* Deprecated HSIntro versions */
+#define PROTOVER_HS_INTRO_DEPRECATED_1 1
+#define PROTOVER_HS_INTRO_DEPRECATED_2 2
-/* HSv2 Rend and HSDir protocol versions.
- * Hard-coded here, because they do not appear anywhere in the code. */
+/* HSv2 Rend and HSDir protocol versions. */
#define PROTOVER_HS_RENDEZVOUS_POINT_V2 1
#define PROTOVER_HSDIR_V2 2
-/* DirCache, Desc, Microdesc, and Cons protocol versions.
- * Hard-coded here, because they do not appear anywhere in the code. */
+/* DirCache, Desc, Microdesc, and Cons protocol versions. */
#define PROTOVER_DIRCACHE_V1 1
#define PROTOVER_DIRCACHE_V2 2
@@ -390,6 +366,10 @@ test_protover_supports_version(void *arg)
#define PROTOVER_CONS_V1 1
#define PROTOVER_CONS_V2 2
+#define PROTOVER_PADDING_V1 1
+
+#define PROTOVER_FLOWCTRL_V1 1
+
/* Make sure we haven't forgotten any supported protocols */
static void
test_protover_supported_protocols(void *arg)
@@ -404,24 +384,27 @@ test_protover_supported_protocols(void *arg)
PRT_LINK,
MAX_LINK_PROTO));
for (uint16_t i = 0; i < MAX_PROTOCOLS_TO_TEST; i++) {
- if (is_or_protocol_version_known(i)) {
- tt_assert(protocol_list_supports_protocol(supported_protocols,
+ tt_int_op(protocol_list_supports_protocol(supported_protocols,
PRT_LINK,
- i));
- }
+ i),
+ OP_EQ,
+ is_or_protocol_version_known(i));
}
-#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
- /* Legacy LinkAuth does not appear anywhere in the code. */
- tt_assert(protocol_list_supports_protocol(supported_protocols,
+ /* Legacy LinkAuth is only supported on OpenSSL and similar. */
+ tt_int_op(protocol_list_supports_protocol(supported_protocols,
PRT_LINKAUTH,
- PROTOVER_LINKAUTH_V1));
-#endif
- /* Latest LinkAuth is not exposed in the headers. */
- tt_assert(protocol_list_supports_protocol(supported_protocols,
- PRT_LINKAUTH,
- PROTOVER_LINKAUTH_V3));
- /* Is there any way to test for new LinkAuth? */
+ PROTOVER_LINKAUTH_V1),
+ OP_EQ,
+ authchallenge_type_is_supported(AUTHTYPE_RSA_SHA256_TLSSECRET));
+ /* LinkAuth=2 is unused */
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_LINKAUTH,
+ PROTOVER_LINKAUTH_V2));
+ tt_assert(
+ protocol_list_supports_protocol(supported_protocols,
+ PRT_LINKAUTH,
+ PROTOVER_LINKAUTH_ED25519_HANDSHAKE));
/* Relay protovers do not appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -429,20 +412,32 @@ test_protover_supported_protocols(void *arg)
PROTOVER_RELAY_V1));
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_RELAY,
- PROTOVER_RELAY_V2));
- /* Is there any way to test for new Relay? */
-
- /* We could test legacy HSIntro by calling rend_service_update_descriptor(),
- * and checking the protocols field. But that's unlikely to change, so
- * we just use a hard-coded value. */
+ PROTOVER_RELAY_EXTEND2));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_RELAY,
+ PROTOVER_RELAY_ACCEPT_IPV6));
tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_RELAY,
+ PROTOVER_RELAY_EXTEND_IPV6));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_RELAY,
+ PROTOVER_RELAY_CANONICAL_IPV6));
+
+ /* These HSIntro versions are deprecated */
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_HSINTRO,
+ PROTOVER_HS_INTRO_DEPRECATED_1));
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
PRT_HSINTRO,
- PROTOVER_HSINTRO_V2));
+ PROTOVER_HS_INTRO_DEPRECATED_2));
/* Test for HSv3 HSIntro */
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSINTRO,
PROTOVER_HS_INTRO_V3));
- /* Is there any way to test for new HSIntro? */
+ /* Test for HSIntro DoS */
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_HSINTRO,
+ PROTOVER_HS_INTRO_DOS));
/* Legacy HSRend does not appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -452,7 +447,6 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSREND,
PROTOVER_HS_RENDEZVOUS_POINT_V3));
- /* Is there any way to test for new HSRend? */
/* Legacy HSDir does not appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -462,16 +456,11 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSDIR,
PROTOVER_HSDIR_V3));
- /* Is there any way to test for new HSDir? */
/* No DirCache versions appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_DIRCACHE,
- PROTOVER_DIRCACHE_V1));
- tt_assert(protocol_list_supports_protocol(supported_protocols,
- PRT_DIRCACHE,
PROTOVER_DIRCACHE_V2));
- /* Is there any way to test for new DirCache? */
/* No Desc versions appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -489,7 +478,6 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_MICRODESC,
PROTOVER_MICRODESC_V2));
- /* Is there any way to test for new Microdesc? */
/* No Cons versions appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -498,7 +486,19 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_CONS,
PROTOVER_CONS_V2));
- /* Is there any way to test for new Cons? */
+
+ /* Padding=1 is deprecated. */
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_PADDING,
+ PROTOVER_PADDING_V1));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_PADDING,
+ PROTOVER_HS_SETUP_PADDING));
+
+ /* FlowCtrl */
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_FLOWCTRL,
+ PROTOVER_FLOWCTRL_V1));
done:
;
@@ -529,6 +529,10 @@ test_protover_vote_roundtrip(void *args)
{ "N-1=1,2", "N-1=1-2" },
{ "-1=4294967295", NULL },
{ "-1=3", "-1=3" },
+ { "Foo=,", NULL },
+ { "Foo=,1", NULL },
+ { "Foo=1,,3", NULL },
+ { "Foo=1,3,", NULL },
/* junk. */
{ "!!3@*", NULL },
/* Missing equals sign */
@@ -587,6 +591,265 @@ 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(),
+ protover_get_recommended_client_protocols(),
+ protover_get_recommended_relay_protocols(),
+ protover_get_required_client_protocols(),
+ protover_get_required_relay_protocols(),
+ };
+ 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);
+}
+
+/* Stringifies its argument.
+ * 4 -> "4" */
+#define STR(x) #x
+
+#ifdef COCCI
+#define PROTOVER(proto_string, version_macro)
+#else
+/* Generate a protocol version string using proto_string and version_macro.
+ * PROTOVER("HSIntro", PROTOVER_HS_INTRO_DOS) -> "HSIntro" "=" "5"
+ * Uses two levels of macros to turn PROTOVER_HS_INTRO_DOS into "5".
+ */
+#define PROTOVER(proto_string, version_macro) \
+ (proto_string "=" STR(version_macro))
+#endif
+
+#define DEBUG_PROTOVER(flags) \
+ STMT_BEGIN \
+ log_debug(LD_GENERAL, \
+ "protovers:\n" \
+ "protocols_known: %d,\n" \
+ "supports_extend2_cells: %d,\n" \
+ "supports_accepting_ipv6_extends: %d,\n" \
+ "supports_initiating_ipv6_extends: %d,\n" \
+ "supports_canonical_ipv6_conns: %d,\n" \
+ "supports_ed25519_link_handshake_compat: %d,\n" \
+ "supports_ed25519_link_handshake_any: %d,\n" \
+ "supports_ed25519_hs_intro: %d,\n" \
+ "supports_establish_intro_dos_extension: %d,\n" \
+ "supports_v3_hsdir: %d,\n" \
+ "supports_v3_rendezvous_point: %d,\n" \
+ "supports_hs_setup_padding: %d.", \
+ (flags).protocols_known, \
+ (flags).supports_extend2_cells, \
+ (flags).supports_accepting_ipv6_extends, \
+ (flags).supports_initiating_ipv6_extends, \
+ (flags).supports_canonical_ipv6_conns, \
+ (flags).supports_ed25519_link_handshake_compat, \
+ (flags).supports_ed25519_link_handshake_any, \
+ (flags).supports_ed25519_hs_intro, \
+ (flags).supports_establish_intro_dos_extension, \
+ (flags).supports_v3_hsdir, \
+ (flags).supports_v3_rendezvous_point, \
+ (flags).supports_hs_setup_padding); \
+ STMT_END
+
+/* Test that the proto_string version version_macro sets summary_flag. */
+#define TEST_PROTOVER(proto_string, version_macro, summary_flag) \
+ STMT_BEGIN \
+ memset(&flags, 0, sizeof(flags)); \
+ summarize_protover_flags(&flags, \
+ PROTOVER(proto_string, version_macro), \
+ NULL); \
+ DEBUG_PROTOVER(flags); \
+ tt_int_op(flags.protocols_known, OP_EQ, 1); \
+ tt_int_op(flags.summary_flag, OP_EQ, 1); \
+ flags.protocols_known = 0; \
+ flags.summary_flag = 0; \
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags)); \
+ STMT_END
+
+static void
+test_protover_summarize_flags(void *args)
+{
+ (void) args;
+ char pv[30];
+ memset(&pv, 0, sizeof(pv));
+
+ protover_summary_cache_free_all();
+
+ protover_summary_flags_t zero_flags;
+ memset(&zero_flags, 0, sizeof(zero_flags));
+ protover_summary_flags_t flags;
+
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags, NULL, NULL);
+ DEBUG_PROTOVER(flags);
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags, "", "");
+ DEBUG_PROTOVER(flags);
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Now check version exceptions */
+
+ /* EXTEND2 cell support */
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags, NULL, "Tor 0.2.4.8-alpha");
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_extend2_cells, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_extend2_cells = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* disabling HSDir v3 support for buggy versions */
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags,
+ PROTOVER("HSDir", PROTOVER_HSDIR_V3),
+ NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_v3_hsdir, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_v3_hsdir = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags,
+ PROTOVER("HSDir", PROTOVER_HSDIR_V3),
+ "Tor 0.3.0.7");
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ /* Now clear that flag, and check the rest are zero */
+ flags.protocols_known = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Now check standard summaries */
+
+ /* LinkAuth */
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags,
+ PROTOVER("LinkAuth",
+ PROTOVER_LINKAUTH_ED25519_HANDSHAKE),
+ NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_ed25519_link_handshake_compat = 0;
+ flags.supports_ed25519_link_handshake_any = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Test one greater */
+ memset(&flags, 0, sizeof(flags));
+ snprintf(pv, sizeof(pv),
+ "%s=%d", "LinkAuth", PROTOVER_LINKAUTH_ED25519_HANDSHAKE + 1);
+ summarize_protover_flags(&flags, pv, NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 0);
+ tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_ed25519_link_handshake_compat = 0;
+ flags.supports_ed25519_link_handshake_any = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Test one less */
+ memset(&flags, 0, sizeof(flags));
+ snprintf(pv, sizeof(pv),
+ "%s=%d", "LinkAuth", PROTOVER_LINKAUTH_ED25519_HANDSHAKE - 1);
+ summarize_protover_flags(&flags, pv, NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 0);
+ tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 0);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_ed25519_link_handshake_compat = 0;
+ flags.supports_ed25519_link_handshake_any = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* We don't test "one more" and "one less" for each protocol version.
+ * But that could be a useful thing to add. */
+
+ /* Relay */
+ memset(&flags, 0, sizeof(flags));
+ /* This test relies on these versions being equal */
+ tt_int_op(PROTOVER_RELAY_EXTEND2, OP_EQ, PROTOVER_RELAY_ACCEPT_IPV6);
+ summarize_protover_flags(&flags,
+ PROTOVER("Relay", PROTOVER_RELAY_EXTEND2), NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_extend2_cells, OP_EQ, 1);
+ tt_int_op(flags.supports_accepting_ipv6_extends, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_extend2_cells = 0;
+ flags.supports_accepting_ipv6_extends = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ memset(&flags, 0, sizeof(flags));
+ /* This test relies on these versions being equal */
+ tt_int_op(PROTOVER_RELAY_EXTEND_IPV6, OP_EQ, PROTOVER_RELAY_CANONICAL_IPV6);
+ summarize_protover_flags(&flags,
+ PROTOVER("Relay", PROTOVER_RELAY_EXTEND_IPV6),
+ NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_accepting_ipv6_extends, OP_EQ, 1);
+ tt_int_op(flags.supports_initiating_ipv6_extends, OP_EQ, 1);
+ tt_int_op(flags.supports_canonical_ipv6_conns, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_accepting_ipv6_extends = 0;
+ flags.supports_initiating_ipv6_extends = 0;
+ flags.supports_canonical_ipv6_conns = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ TEST_PROTOVER("HSIntro", PROTOVER_HS_INTRO_V3,
+ supports_ed25519_hs_intro);
+ TEST_PROTOVER("HSIntro", PROTOVER_HS_INTRO_DOS,
+ supports_establish_intro_dos_extension);
+
+ TEST_PROTOVER("HSRend", PROTOVER_HS_RENDEZVOUS_POINT_V3,
+ supports_v3_rendezvous_point);
+
+ TEST_PROTOVER("HSDir", PROTOVER_HSDIR_V3,
+ supports_v3_hsdir);
+
+ TEST_PROTOVER("Padding", PROTOVER_HS_SETUP_PADDING,
+ supports_hs_setup_padding);
+
+ done:
+ ;
+}
+
#define PV_TEST(name, flags) \
{ #name, test_protover_ ##name, (flags), NULL, NULL }
@@ -600,5 +863,8 @@ 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),
+ /* fork, because we memoize flags internally */
+ PV_TEST(summarize_flags, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index 1f9786648a..893fec3674 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -1,28 +1,30 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define PT_PRIVATE
-#define UTIL_PRIVATE
#define STATEFILE_PRIVATE
-#define CONTROL_PRIVATE
-#define SUBPROCESS_PRIVATE
+#define CONTROL_EVENTS_PRIVATE
+#define PROCESS_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
-#include "app/config/confparse.h"
+#include "lib/confmgt/confmgt.h"
#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "feature/client/transports.h"
#include "core/or/circuitbuild.h"
#include "app/config/statefile.h"
#include "test/test.h"
-#include "lib/process/subprocess.h"
#include "lib/encoding/confline.h"
#include "lib/net/resolve.h"
+#include "lib/process/process.h"
#include "app/config/or_state_st.h"
+#include "test/log_test_helpers.h"
+
static void
reset_mp(managed_proxy_t *mp)
{
@@ -288,41 +290,35 @@ test_pt_get_extrainfo_string(void *arg)
tor_free(s);
}
-#ifdef _WIN32
-#define STDIN_HANDLE HANDLE*
-#else
-#define STDIN_HANDLE int
-#endif
-
-static smartlist_t *
-tor_get_lines_from_handle_replacement(STDIN_HANDLE handle,
- enum stream_status *stream_status_out)
+static int
+process_read_stdout_replacement(process_t *process, buf_t *buffer)
{
+ (void)process;
static int times_called = 0;
- smartlist_t *retval_sl = smartlist_new();
-
- (void) handle;
- (void) stream_status_out;
/* Generate some dummy CMETHOD lines the first 5 times. The 6th
time, send 'CMETHODS DONE' to finish configuring the proxy. */
- if (times_called++ != 5) {
- smartlist_add_asprintf(retval_sl, "SMETHOD mock%d 127.0.0.1:555%d",
+ times_called++;
+
+ if (times_called <= 5) {
+ buf_add_printf(buffer, "SMETHOD mock%d 127.0.0.1:555%d\n",
times_called, times_called);
- } else {
- smartlist_add_strdup(retval_sl, "SMETHODS DONE");
+ } else if (times_called <= 6) {
+ buf_add_string(buffer, "SMETHODS DONE\n");
+ } else if (times_called <= 7) {
+ buf_add_string(buffer, "LOG SEVERITY=error MESSAGE=\"Oh noes, something "
+ "bad happened. What do we do!?\"\n");
+ buf_add_string(buffer, "LOG SEVERITY=warning MESSAGE=\"warning msg\"\n");
+ buf_add_string(buffer, "LOG SEVERITY=notice MESSAGE=\"notice msg\"\n");
+ buf_add_string(buffer, "LOG SEVERITY=info MESSAGE=\"info msg\"\n");
+ buf_add_string(buffer, "LOG SEVERITY=debug MESSAGE=\"debug msg\"\n");
+ } else if (times_called <= 8) {
+ buf_add_string(buffer, "STATUS TRANSPORT=a K_1=a K_2=b K_3=\"foo bar\"\n");
+ buf_add_string(buffer, "STATUS TRANSPORT=b K_1=a K_2=b K_3=\"foo bar\"\n");
+ buf_add_string(buffer, "STATUS TRANSPORT=c K_1=a K_2=b K_3=\"foo bar\"\n");
}
- return retval_sl;
-}
-
-/* NOP mock */
-static void
-tor_process_handle_destroy_replacement(process_handle_t *process_handle,
- int also_terminate_process)
-{
- (void) process_handle;
- (void) also_terminate_process;
+ return (int)buf_datalen(buffer);
}
static or_state_t *dummy_state = NULL;
@@ -355,12 +351,9 @@ test_pt_configure_proxy(void *arg)
managed_proxy_t *mp = NULL;
(void) arg;
- dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_state = or_state_new();
- MOCK(tor_get_lines_from_handle,
- tor_get_lines_from_handle_replacement);
- MOCK(tor_process_handle_destroy,
- tor_process_handle_destroy_replacement);
+ MOCK(process_read_stdout, process_read_stdout_replacement);
MOCK(get_or_state,
get_or_state_replacement);
MOCK(queue_control_event_string,
@@ -372,24 +365,34 @@ test_pt_configure_proxy(void *arg)
mp->conf_state = PT_PROTO_ACCEPTING_METHODS;
mp->transports = smartlist_new();
mp->transports_to_launch = smartlist_new();
- mp->process_handle = tor_malloc_zero(sizeof(process_handle_t));
mp->argv = tor_malloc_zero(sizeof(char*)*2);
mp->argv[0] = tor_strdup("<testcase>");
mp->is_server = 1;
+ /* Configure the process. */
+ mp->process = process_new("");
+ process_set_stdout_read_callback(mp->process, managed_proxy_stdout_callback);
+ process_set_data(mp->process, mp);
+
/* Test the return value of configure_proxy() by calling it some
times while it is uninitialized and then finally finalizing its
configuration. */
for (i = 0 ; i < 5 ; i++) {
+ /* force a read from our mocked stdout reader. */
+ process_notify_event_stdout(mp->process);
+ /* try to configure our proxy. */
retval = configure_proxy(mp);
/* retval should be zero because proxy hasn't finished configuring yet */
tt_int_op(retval, OP_EQ, 0);
/* check the number of registered transports */
- tt_assert(smartlist_len(mp->transports) == i+1);
+ tt_int_op(smartlist_len(mp->transports), OP_EQ, i+1);
/* check that the mp is still waiting for transports */
tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
}
+ /* Get the SMETHOD DONE written to the process. */
+ process_notify_event_stdout(mp->process);
+
/* this last configure_proxy() should finalize the proxy configuration. */
retval = configure_proxy(mp);
/* retval should be 1 since the proxy finished configuring */
@@ -412,6 +415,49 @@ test_pt_configure_proxy(void *arg)
tt_str_op(smartlist_get(controlevent_msgs, 4), OP_EQ,
"650 TRANSPORT_LAUNCHED server mock5 127.0.0.1 5555\r\n");
+ /* Get the log message out. */
+ setup_full_capture_of_logs(LOG_ERR);
+ process_notify_event_stdout(mp->process);
+ expect_single_log_msg_containing("Oh noes, something bad happened");
+ teardown_capture_of_logs();
+
+ tt_int_op(controlevent_n, OP_EQ, 10);
+ tt_int_op(controlevent_event, OP_EQ, EVENT_PT_LOG);
+ tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 10);
+ tt_str_op(smartlist_get(controlevent_msgs, 5), OP_EQ,
+ "650 PT_LOG PT=<testcase> SEVERITY=error "
+ "MESSAGE=\"Oh noes, "
+ "something bad happened. What do we do!?\"\r\n");
+ tt_str_op(smartlist_get(controlevent_msgs, 6), OP_EQ,
+ "650 PT_LOG PT=<testcase> SEVERITY=warning "
+ "MESSAGE=\"warning msg\"\r\n");
+ tt_str_op(smartlist_get(controlevent_msgs, 7), OP_EQ,
+ "650 PT_LOG PT=<testcase> SEVERITY=notice "
+ "MESSAGE=\"notice msg\"\r\n");
+ tt_str_op(smartlist_get(controlevent_msgs, 8), OP_EQ,
+ "650 PT_LOG PT=<testcase> SEVERITY=info "
+ "MESSAGE=\"info msg\"\r\n");
+ tt_str_op(smartlist_get(controlevent_msgs, 9), OP_EQ,
+ "650 PT_LOG PT=<testcase> SEVERITY=debug "
+ "MESSAGE=\"debug msg\"\r\n");
+
+ /* Get the STATUS messages out. */
+ process_notify_event_stdout(mp->process);
+
+ tt_int_op(controlevent_n, OP_EQ, 13);
+ tt_int_op(controlevent_event, OP_EQ, EVENT_PT_STATUS);
+ tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 13);
+
+ tt_str_op(smartlist_get(controlevent_msgs, 10), OP_EQ,
+ "650 PT_STATUS "
+ "PT=<testcase> TRANSPORT=a K_1=a K_2=b K_3=\"foo bar\"\r\n");
+ tt_str_op(smartlist_get(controlevent_msgs, 11), OP_EQ,
+ "650 PT_STATUS "
+ "PT=<testcase> TRANSPORT=b K_1=a K_2=b K_3=\"foo bar\"\r\n");
+ tt_str_op(smartlist_get(controlevent_msgs, 12), OP_EQ,
+ "650 PT_STATUS "
+ "PT=<testcase> TRANSPORT=c K_1=a K_2=b K_3=\"foo bar\"\r\n");
+
{ /* check that the transport info were saved properly in the tor state */
config_line_t *transport_in_state = NULL;
smartlist_t *transport_info_sl = smartlist_new();
@@ -434,9 +480,9 @@ test_pt_configure_proxy(void *arg)
}
done:
+ teardown_capture_of_logs();
or_state_free(dummy_state);
- UNMOCK(tor_get_lines_from_handle);
- UNMOCK(tor_process_handle_destroy);
+ UNMOCK(process_read_stdout);
UNMOCK(get_or_state);
UNMOCK(queue_control_event_string);
if (controlevent_msgs) {
@@ -449,7 +495,7 @@ test_pt_configure_proxy(void *arg)
smartlist_free(mp->transports);
}
smartlist_free(mp->transports_to_launch);
- tor_free(mp->process_handle);
+ process_free(mp->process);
tor_free(mp->argv[0]);
tor_free(mp->argv);
tor_free(mp);
@@ -533,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_ptr_slow.c b/src/test/test_ptr_slow.c
new file mode 100644
index 0000000000..25b893c4c0
--- /dev/null
+++ b/src/test/test_ptr_slow.c
@@ -0,0 +1,106 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "test/test.h"
+#include "test/ptr_helpers.h"
+
+#include <stdint.h>
+#include <limits.h>
+
+/** Assert that <b>a</b> can be cast to void * and back. */
+static void
+assert_int_voidptr_roundtrip(int a)
+{
+ intptr_t ap = (intptr_t)a;
+ void *b = cast_intptr_to_voidstar(ap);
+ intptr_t c = cast_voidstar_to_intptr(b);
+ void *d = cast_intptr_to_voidstar(c);
+
+ tt_assert(ap == c);
+ tt_assert(b == d);
+
+ done:
+ return;
+}
+
+/** Test for possibility of casting `int` to `void *` and back. */
+static void
+test_int_voidstar_interop(void *arg)
+{
+ int a;
+ (void)arg;
+
+ for (a = -1024; a <= 1024; a++) {
+ assert_int_voidptr_roundtrip(a);
+ }
+
+ for (a = INT_MIN; a <= INT_MIN+1024; a++) {
+ assert_int_voidptr_roundtrip(a);
+ }
+
+ for (a = INT_MAX-1024; a < INT_MAX; a++) {
+ assert_int_voidptr_roundtrip(a);
+ }
+
+ a = 1;
+ for (unsigned long i = 0; i < sizeof(int) * 8; i++) {
+ assert_int_voidptr_roundtrip(a);
+ a = (a << 1);
+ }
+}
+
+/** Assert that <b>a</b> can be cast to void * and back. */
+static void
+assert_uint_voidptr_roundtrip(unsigned int a)
+{
+ uintptr_t ap = (uintptr_t)a;
+ void *b = cast_uintptr_to_voidstar(ap);
+ uintptr_t c = cast_voidstar_to_uintptr(b);
+ void *d = cast_uintptr_to_voidstar(c);
+
+ tt_assert(ap == c);
+ tt_assert(b == d);
+
+ done:
+ return;
+}
+
+/** Test for possibility of casting `int` to `void *` and back. */
+static void
+test_uint_voidstar_interop(void *arg)
+{
+ unsigned int a;
+ (void)arg;
+
+ for (a = 0; a <= 1024; a++) {
+ assert_uint_voidptr_roundtrip(a);
+ }
+
+ for (a = UINT_MAX-1024; a < UINT_MAX; a++) {
+ assert_uint_voidptr_roundtrip(a);
+ }
+
+ a = 1;
+ for (unsigned long i = 0; i < sizeof(int) * 8; i++) {
+ assert_uint_voidptr_roundtrip(a);
+ a = (a << 1);
+ }
+}
+
+struct testcase_t slow_ptr_tests[] = {
+ { .name = "int_voidstar_interop",
+ .fn = test_int_voidstar_interop,
+ .flags = 0,
+ .setup = NULL,
+ .setup_data = NULL },
+ { .name = "uint_voidstar_interop",
+ .fn = test_uint_voidstar_interop,
+ .flags = 0,
+ .setup = NULL,
+ .setup_data = NULL },
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_pubsub_build.c b/src/test/test_pubsub_build.c
new file mode 100644
index 0000000000..5f9005926c
--- /dev/null
+++ b/src/test/test_pubsub_build.c
@@ -0,0 +1,578 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define DISPATCH_PRIVATE
+#define PUBSUB_PRIVATE
+
+#include "test/test.h"
+
+#include "lib/cc/torint.h"
+#include "lib/dispatch/dispatch.h"
+#include "lib/dispatch/dispatch_naming.h"
+#include "lib/dispatch/dispatch_st.h"
+#include "lib/dispatch/msgtypes.h"
+#include "lib/pubsub/pubsub_macros.h"
+#include "lib/pubsub/pubsub_build.h"
+#include "lib/pubsub/pubsub_builder_st.h"
+
+#include "lib/log/escape.h"
+#include "lib/malloc/malloc.h"
+#include "lib/string/printf.h"
+
+#include "test/log_test_helpers.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static char *
+ex_int_fmt(msg_aux_data_t aux)
+{
+ int val = (int) aux.u64;
+ char *r=NULL;
+ tor_asprintf(&r, "%d", val);
+ return r;
+}
+
+static char *
+ex_str_fmt(msg_aux_data_t aux)
+{
+ return esc_for_log(aux.ptr);
+}
+
+static void
+ex_str_free(msg_aux_data_t aux)
+{
+ tor_free_(aux.ptr);
+}
+
+static dispatch_typefns_t intfns = {
+ .fmt_fn = ex_int_fmt
+};
+
+static dispatch_typefns_t stringfns = {
+ .free_fn = ex_str_free,
+ .fmt_fn = ex_str_fmt
+};
+
+DECLARE_MESSAGE_INT(bunch_of_coconuts, int, int);
+DECLARE_PUBLISH(bunch_of_coconuts);
+DECLARE_SUBSCRIBE(bunch_of_coconuts, coconut_recipient_cb);
+
+DECLARE_MESSAGE(yes_we_have_no, string, char *);
+DECLARE_PUBLISH(yes_we_have_no);
+DECLARE_SUBSCRIBE(yes_we_have_no, absent_item_cb);
+
+static void
+coconut_recipient_cb(const msg_t *m, int n_coconuts)
+{
+ (void)m;
+ (void)n_coconuts;
+}
+
+static void
+absent_item_cb(const msg_t *m, const char *fruitname)
+{
+ (void)m;
+ (void)fruitname;
+}
+
+#define FLAG_SKIP 99999
+
+static void
+seed_dispatch_builder(pubsub_builder_t *b,
+ unsigned fl1, unsigned fl2, unsigned fl3, unsigned fl4)
+{
+ pubsub_connector_t *c = NULL;
+
+ {
+ c = pubsub_connector_for_subsystem(b, get_subsys_id("sys1"));
+ DISPATCH_REGISTER_TYPE(c, int, &intfns);
+ if (fl1 != FLAG_SKIP)
+ DISPATCH_ADD_PUB_(c, main, bunch_of_coconuts, fl1);
+ if (fl2 != FLAG_SKIP)
+ DISPATCH_ADD_SUB_(c, main, yes_we_have_no, fl2);
+ pubsub_connector_free(c);
+ }
+
+ {
+ c = pubsub_connector_for_subsystem(b, get_subsys_id("sys2"));
+ DISPATCH_REGISTER_TYPE(c, string, &stringfns);
+ if (fl3 != FLAG_SKIP)
+ DISPATCH_ADD_PUB_(c, main, yes_we_have_no, fl3);
+ if (fl4 != FLAG_SKIP)
+ DISPATCH_ADD_SUB_(c, main, bunch_of_coconuts, fl4);
+ pubsub_connector_free(c);
+ }
+}
+
+static void
+seed_pubsub_builder_basic(pubsub_builder_t *b)
+{
+ seed_dispatch_builder(b, 0, 0, 0, 0);
+}
+
+/* Regular builder with valid types and messages.
+ */
+static void
+test_pubsub_build_types_ok(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+ pubsub_connector_t *c = NULL;
+ pubsub_items_t *items = NULL;
+
+ b = pubsub_builder_new();
+ seed_pubsub_builder_basic(b);
+
+ dispatcher = pubsub_builder_finalize(b, &items);
+ b = NULL;
+ tt_assert(dispatcher);
+ tt_assert(items);
+ tt_int_op(smartlist_len(items->items), OP_EQ, 4);
+
+ // Make sure that the bindings got build correctly.
+ SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, item) {
+ if (item->is_publish) {
+ tt_assert(item->pub_binding);
+ tt_ptr_op(item->pub_binding->dispatch_ptr, OP_EQ, dispatcher);
+ }
+ } SMARTLIST_FOREACH_END(item);
+
+ tt_int_op(dispatcher->n_types, OP_GE, 2);
+ tt_assert(dispatcher->typefns);
+
+ tt_assert(dispatcher->typefns[get_msg_type_id("int")].fmt_fn == ex_int_fmt);
+ tt_assert(dispatcher->typefns[get_msg_type_id("string")].fmt_fn ==
+ ex_str_fmt);
+
+ // Now clear the bindings, like we would do before freeing the
+ // the dispatcher.
+ pubsub_items_clear_bindings(items);
+ SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, item) {
+ if (item->is_publish) {
+ tt_assert(item->pub_binding);
+ tt_ptr_op(item->pub_binding->dispatch_ptr, OP_EQ, NULL);
+ }
+ } SMARTLIST_FOREACH_END(item);
+
+ done:
+ pubsub_connector_free(c);
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+ pubsub_items_free(items);
+}
+
+/* We fail if the same type is defined in two places with different functions.
+ */
+static void
+test_pubsub_build_types_decls_conflict(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+ pubsub_connector_t *c = NULL;
+
+ b = pubsub_builder_new();
+ seed_pubsub_builder_basic(b);
+ {
+ c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3"));
+ // Extra declaration of int: we don't allow this.
+ DISPATCH_REGISTER_TYPE(c, int, &stringfns);
+ pubsub_connector_free(c);
+ }
+
+ setup_full_capture_of_logs(LOG_WARN);
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher == NULL);
+ // expect_log_msg_containing("(int) declared twice"); // XXXX
+
+ done:
+ pubsub_connector_free(c);
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+ teardown_capture_of_logs();
+}
+
+/* If a message ID exists but nobody is publishing or subscribing to it,
+ * that's okay. */
+static void
+test_pubsub_build_unused_message(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+
+ b = pubsub_builder_new();
+ seed_pubsub_builder_basic(b);
+
+ // This message isn't actually generated by anyone, but that will be fine:
+ // we just log it at info.
+ get_message_id("unused");
+ setup_capture_of_logs(LOG_INFO);
+
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher);
+ expect_log_msg_containing(
+ "Nobody is publishing or subscribing to message");
+
+ done:
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+ teardown_capture_of_logs();
+}
+
+/* Publishing or subscribing to a message with no subscribers / publishers
+ * should fail and warn. */
+static void
+test_pubsub_build_missing_pubsub(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+
+ b = pubsub_builder_new();
+ seed_dispatch_builder(b, 0, 0, FLAG_SKIP, FLAG_SKIP);
+
+ setup_full_capture_of_logs(LOG_WARN);
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher == NULL);
+
+ expect_log_msg_containing(
+ "Message \"bunch_of_coconuts\" has publishers, but no subscribers.");
+ expect_log_msg_containing(
+ "Message \"yes_we_have_no\" has subscribers, but no publishers.");
+
+ done:
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+ teardown_capture_of_logs();
+}
+
+/* Make sure that a stub publisher or subscriber prevents an error from
+ * happening even if there are no other publishers/subscribers for a message
+ */
+static void
+test_pubsub_build_stub_pubsub(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+
+ b = pubsub_builder_new();
+ seed_dispatch_builder(b, 0, 0, DISP_FLAG_STUB, DISP_FLAG_STUB);
+
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher);
+
+ // 1 subscriber.
+ tt_int_op(1, OP_EQ,
+ dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled);
+ // no subscribers
+ tt_ptr_op(NULL, OP_EQ,
+ dispatcher->table[get_message_id("bunch_of_coconuts")]);
+
+ done:
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+}
+
+/* Only one channel per msg id. */
+static void
+test_pubsub_build_channels_conflict(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+ pubsub_connector_t *c = NULL;
+
+ b = pubsub_builder_new();
+ seed_pubsub_builder_basic(b);
+ pub_binding_t btmp;
+
+ {
+ c = pubsub_connector_for_subsystem(b, get_subsys_id("problems"));
+ /* Usually the DISPATCH_ADD_PUB macro would keep us from using
+ * the wrong channel */
+ pubsub_add_pub_(c, &btmp, get_channel_id("hithere"),
+ get_message_id("bunch_of_coconuts"),
+ get_msg_type_id("int"),
+ 0 /* flags */,
+ "somewhere.c", 22);
+ pubsub_connector_free(c);
+ };
+
+ setup_full_capture_of_logs(LOG_WARN);
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher == NULL);
+
+ expect_log_msg_containing("Message \"bunch_of_coconuts\" is associated "
+ "with multiple inconsistent channels.");
+
+ done:
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+ teardown_capture_of_logs();
+}
+
+/* Only one type per msg id. */
+static void
+test_pubsub_build_types_conflict(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+ pubsub_connector_t *c = NULL;
+
+ b = pubsub_builder_new();
+ seed_pubsub_builder_basic(b);
+ pub_binding_t btmp;
+
+ {
+ c = pubsub_connector_for_subsystem(b, get_subsys_id("problems"));
+ /* Usually the DISPATCH_ADD_PUB macro would keep us from using
+ * the wrong channel */
+ pubsub_add_pub_(c, &btmp, get_channel_id("hithere"),
+ get_message_id("bunch_of_coconuts"),
+ get_msg_type_id("string"),
+ 0 /* flags */,
+ "somewhere.c", 22);
+ pubsub_connector_free(c);
+ };
+
+ setup_full_capture_of_logs(LOG_WARN);
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher == NULL);
+
+ expect_log_msg_containing("Message \"bunch_of_coconuts\" is associated "
+ "with multiple inconsistent message types.");
+
+ done:
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+ teardown_capture_of_logs();
+}
+
+/* The same module can't publish and subscribe the same message */
+static void
+test_pubsub_build_pubsub_same(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+ pubsub_connector_t *c = NULL;
+
+ b = pubsub_builder_new();
+ seed_pubsub_builder_basic(b);
+
+ {
+ c = pubsub_connector_for_subsystem(b, get_subsys_id("sys1"));
+ // already publishing this.
+ DISPATCH_ADD_SUB(c, main, bunch_of_coconuts);
+ pubsub_connector_free(c);
+ };
+
+ setup_full_capture_of_logs(LOG_WARN);
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher == NULL);
+
+ expect_log_msg_containing("Message \"bunch_of_coconuts\" is published "
+ "and subscribed by the same subsystem \"sys1\".");
+
+ done:
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+ teardown_capture_of_logs();
+}
+
+/* More than one subsystem may publish or subscribe, and that's okay. */
+static void
+test_pubsub_build_pubsub_multi(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+ pubsub_connector_t *c = NULL;
+
+ b = pubsub_builder_new();
+ seed_pubsub_builder_basic(b);
+ pub_binding_t btmp;
+
+ {
+ c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3"));
+ DISPATCH_ADD_SUB(c, main, bunch_of_coconuts);
+ pubsub_add_pub_(c, &btmp, get_channel_id("main"),
+ get_message_id("yes_we_have_no"),
+ get_msg_type_id("string"),
+ 0 /* flags */,
+ "somewhere.c", 22);
+ pubsub_connector_free(c);
+ };
+
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher);
+
+ // 1 subscribers
+ tt_int_op(1, OP_EQ,
+ dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled);
+ // 2 subscribers.
+ dtbl_entry_t *ent =
+ dispatcher->table[get_message_id("bunch_of_coconuts")];
+ tt_int_op(2, OP_EQ, ent->n_enabled);
+ tt_int_op(2, OP_EQ, ent->n_fns);
+ tt_ptr_op(ent->rcv[0].fn, OP_EQ, recv_fn__bunch_of_coconuts);
+ tt_ptr_op(ent->rcv[1].fn, OP_EQ, recv_fn__bunch_of_coconuts);
+
+ done:
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+}
+
+static void
+some_other_coconut_hook(const msg_t *m)
+{
+ (void)m;
+}
+
+/* Subscribe hooks should be build correctly when there are a bunch of
+ * them. */
+static void
+test_pubsub_build_sub_many(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+ pubsub_connector_t *c = NULL;
+ char *sysname = NULL;
+ b = pubsub_builder_new();
+ seed_pubsub_builder_basic(b);
+
+ int i;
+ for (i = 1; i < 100; ++i) {
+ tor_asprintf(&sysname, "system%d",i);
+ c = pubsub_connector_for_subsystem(b, get_subsys_id(sysname));
+ if (i % 7) {
+ DISPATCH_ADD_SUB(c, main, bunch_of_coconuts);
+ } else {
+ pubsub_add_sub_(c, some_other_coconut_hook,
+ get_channel_id("main"),
+ get_message_id("bunch_of_coconuts"),
+ get_msg_type_id("int"),
+ 0 /* flags */,
+ "somewhere.c", 22);
+ }
+ pubsub_connector_free(c);
+ tor_free(sysname);
+ };
+
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher);
+
+ dtbl_entry_t *ent =
+ dispatcher->table[get_message_id("bunch_of_coconuts")];
+ tt_int_op(100, OP_EQ, ent->n_enabled);
+ tt_int_op(100, OP_EQ, ent->n_fns);
+ tt_ptr_op(ent->rcv[0].fn, OP_EQ, recv_fn__bunch_of_coconuts);
+ tt_ptr_op(ent->rcv[1].fn, OP_EQ, recv_fn__bunch_of_coconuts);
+ tt_ptr_op(ent->rcv[76].fn, OP_EQ, recv_fn__bunch_of_coconuts);
+ tt_ptr_op(ent->rcv[77].fn, OP_EQ, some_other_coconut_hook);
+ tt_ptr_op(ent->rcv[78].fn, OP_EQ, recv_fn__bunch_of_coconuts);
+
+ done:
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+ tor_free(sysname);
+}
+
+/* It's fine to declare the excl flag. */
+static void
+test_pubsub_build_excl_ok(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+
+ b = pubsub_builder_new();
+ // Try one excl/excl pair and one excl/non pair.
+ seed_dispatch_builder(b, DISP_FLAG_EXCL, 0,
+ DISP_FLAG_EXCL, DISP_FLAG_EXCL);
+
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher);
+
+ // 1 subscribers
+ tt_int_op(1, OP_EQ,
+ dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled);
+ // 1 subscriber.
+ tt_int_op(1, OP_EQ,
+ dispatcher->table[get_message_id("bunch_of_coconuts")]->n_enabled);
+
+ done:
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+}
+
+/* but if you declare the excl flag, you need to mean it. */
+static void
+test_pubsub_build_excl_bad(void *arg)
+{
+ (void)arg;
+ pubsub_builder_t *b = NULL;
+ dispatch_t *dispatcher = NULL;
+ pubsub_connector_t *c = NULL;
+
+ b = pubsub_builder_new();
+ seed_dispatch_builder(b, DISP_FLAG_EXCL, DISP_FLAG_EXCL,
+ 0, 0);
+
+ {
+ c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3"));
+ DISPATCH_ADD_PUB_(c, main, bunch_of_coconuts, 0);
+ DISPATCH_ADD_SUB_(c, main, yes_we_have_no, 0);
+ pubsub_connector_free(c);
+ };
+
+ setup_full_capture_of_logs(LOG_WARN);
+ dispatcher = pubsub_builder_finalize(b, NULL);
+ b = NULL;
+ tt_assert(dispatcher == NULL);
+
+ expect_log_msg_containing("has multiple publishers, but at least one is "
+ "marked as exclusive.");
+ expect_log_msg_containing("has multiple subscribers, but at least one is "
+ "marked as exclusive.");
+
+ done:
+ pubsub_builder_free(b);
+ dispatch_free(dispatcher);
+ teardown_capture_of_logs();
+}
+
+#define T(name, flags) \
+ { #name, test_pubsub_build_ ## name , (flags), NULL, NULL }
+
+struct testcase_t pubsub_build_tests[] = {
+ T(types_ok, TT_FORK),
+ T(types_decls_conflict, TT_FORK),
+ T(unused_message, TT_FORK),
+ T(missing_pubsub, TT_FORK),
+ T(stub_pubsub, TT_FORK),
+ T(channels_conflict, TT_FORK),
+ T(types_conflict, TT_FORK),
+ T(pubsub_same, TT_FORK),
+ T(pubsub_multi, TT_FORK),
+ T(sub_many, TT_FORK),
+ T(excl_ok, TT_FORK),
+ T(excl_bad, TT_FORK),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_pubsub_msg.c b/src/test/test_pubsub_msg.c
new file mode 100644
index 0000000000..3054db885d
--- /dev/null
+++ b/src/test/test_pubsub_msg.c
@@ -0,0 +1,305 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define DISPATCH_PRIVATE
+
+#include "test/test.h"
+
+#include "lib/dispatch/dispatch.h"
+#include "lib/dispatch/dispatch_naming.h"
+#include "lib/dispatch/dispatch_st.h"
+#include "lib/dispatch/msgtypes.h"
+#include "lib/pubsub/pubsub_flags.h"
+#include "lib/pubsub/pub_binding_st.h"
+#include "lib/pubsub/pubsub_build.h"
+#include "lib/pubsub/pubsub_builder_st.h"
+#include "lib/pubsub/pubsub_connect.h"
+#include "lib/pubsub/pubsub_publish.h"
+
+#include "lib/log/escape.h"
+#include "lib/malloc/malloc.h"
+#include "lib/string/printf.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static char *
+ex_str_fmt(msg_aux_data_t aux)
+{
+ return esc_for_log(aux.ptr);
+}
+static void
+ex_str_free(msg_aux_data_t aux)
+{
+ tor_free_(aux.ptr);
+}
+static dispatch_typefns_t stringfns = {
+ .free_fn = ex_str_free,
+ .fmt_fn = ex_str_fmt
+};
+
+// We're using the lowest-level publish/subscribe logic here, to avoid the
+// pubsub_macros.h macros and just test the dispatch core. We'll use a string
+// type for everything.
+
+#define DECLARE_MESSAGE(suffix) \
+ static pub_binding_t pub_binding_##suffix; \
+ static int msg_received_##suffix = 0; \
+ static void recv_msg_##suffix(const msg_t *m) { \
+ (void)m; \
+ ++msg_received_##suffix; \
+ } \
+ EAT_SEMICOLON
+
+#define ADD_PUBLISH(binding_suffix, subsys, channel, msg, flags) \
+ STMT_BEGIN { \
+ con = pubsub_connector_for_subsystem(builder, \
+ get_subsys_id(#subsys)); \
+ pubsub_add_pub_(con, &pub_binding_##binding_suffix, \
+ get_channel_id(#channel), \
+ get_message_id(#msg), get_msg_type_id("string"), \
+ (flags), __FILE__, __LINE__); \
+ pubsub_connector_free(con); \
+ } STMT_END
+
+#define ADD_SUBSCRIBE(hook_suffix, subsys, channel, msg, flags) \
+ STMT_BEGIN { \
+ con = pubsub_connector_for_subsystem(builder, \
+ get_subsys_id(#subsys)); \
+ pubsub_add_sub_(con, recv_msg_##hook_suffix, \
+ get_channel_id(#channel), \
+ get_message_id(#msg), get_msg_type_id("string"), \
+ (flags), __FILE__, __LINE__); \
+ pubsub_connector_free(con); \
+ } STMT_END
+
+#define SEND(binding_suffix, val) \
+ STMT_BEGIN { \
+ msg_aux_data_t data_; \
+ data_.ptr = tor_strdup(val); \
+ pubsub_pub_(&pub_binding_##binding_suffix, data_); \
+ } STMT_END
+
+DECLARE_MESSAGE(msg1);
+DECLARE_MESSAGE(msg2);
+DECLARE_MESSAGE(msg3);
+DECLARE_MESSAGE(msg4);
+DECLARE_MESSAGE(msg5);
+
+static smartlist_t *strings_received = NULL;
+static void
+recv_msg_copy_string(const msg_t *m)
+{
+ const char *s = m->aux_data__.ptr;
+ smartlist_add(strings_received, tor_strdup(s));
+}
+
+static void *
+setup_dispatcher(const struct testcase_t *testcase)
+{
+ (void)testcase;
+ pubsub_builder_t *builder = pubsub_builder_new();
+ pubsub_connector_t *con;
+
+ {
+ con = pubsub_connector_for_subsystem(builder, get_subsys_id("types"));
+ pubsub_connector_register_type_(con,
+ get_msg_type_id("string"),
+ &stringfns,
+ "nowhere.c", 99);
+ pubsub_connector_free(con);
+ }
+ // message1 has one publisher and one subscriber.
+ ADD_PUBLISH(msg1, sys1, main, message1, 0);
+ ADD_SUBSCRIBE(msg1, sys2, main, message1, 0);
+
+ // message2 has a publisher and a stub subscriber.
+ ADD_PUBLISH(msg2, sys1, main, message2, 0);
+ ADD_SUBSCRIBE(msg2, sys2, main, message2, DISP_FLAG_STUB);
+
+ // message3 has a publisher and three subscribers.
+ ADD_PUBLISH(msg3, sys1, main, message3, 0);
+ ADD_SUBSCRIBE(msg3, sys2, main, message3, 0);
+ ADD_SUBSCRIBE(msg3, sys3, main, message3, 0);
+ ADD_SUBSCRIBE(msg3, sys4, main, message3, 0);
+
+ // message4 has one publisher and two subscribers, but it's on another
+ // channel.
+ ADD_PUBLISH(msg4, sys2, other, message4, 0);
+ ADD_SUBSCRIBE(msg4, sys1, other, message4, 0);
+ ADD_SUBSCRIBE(msg4, sys3, other, message4, 0);
+
+ // message5 has a huge number of recipients.
+ ADD_PUBLISH(msg5, sys3, main, message5, 0);
+ ADD_SUBSCRIBE(msg5, sys4, main, message5, 0);
+ ADD_SUBSCRIBE(msg5, sys5, main, message5, 0);
+ ADD_SUBSCRIBE(msg5, sys6, main, message5, 0);
+ ADD_SUBSCRIBE(msg5, sys7, main, message5, 0);
+ ADD_SUBSCRIBE(msg5, sys8, main, message5, 0);
+ for (int i = 0; i < 1000-5; ++i) {
+ char *sys;
+ tor_asprintf(&sys, "xsys-%d", i);
+ con = pubsub_connector_for_subsystem(builder, get_subsys_id(sys));
+ pubsub_add_sub_(con, recv_msg_copy_string,
+ get_channel_id("main"),
+ get_message_id("message5"),
+ get_msg_type_id("string"), 0, "here", 100);
+ pubsub_connector_free(con);
+ tor_free(sys);
+ }
+
+ return pubsub_builder_finalize(builder, NULL);
+}
+
+static int
+cleanup_dispatcher(const struct testcase_t *testcase, void *dispatcher_)
+{
+ (void)testcase;
+ dispatch_t *dispatcher = dispatcher_;
+ dispatch_free(dispatcher);
+ return 1;
+}
+
+static const struct testcase_setup_t dispatcher_setup = {
+ setup_dispatcher, cleanup_dispatcher
+};
+
+static void
+test_pubsub_msg_minimal(void *arg)
+{
+ dispatch_t *d = arg;
+
+ tt_int_op(0, OP_EQ, msg_received_msg1);
+ SEND(msg1, "hello world");
+ tt_int_op(0, OP_EQ, msg_received_msg1); // hasn't actually arrived yet.
+
+ tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 1000));
+ tt_int_op(1, OP_EQ, msg_received_msg1); // we got the message!
+
+ done:
+ ;
+}
+
+static void
+test_pubsub_msg_send_to_stub(void *arg)
+{
+ dispatch_t *d = arg;
+
+ tt_int_op(0, OP_EQ, msg_received_msg2);
+ SEND(msg2, "hello silence");
+ tt_int_op(0, OP_EQ, msg_received_msg2); // hasn't actually arrived yet.
+
+ tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 1000));
+ tt_int_op(0, OP_EQ, msg_received_msg2); // doesn't arrive -- stub hook.
+
+ done:
+ ;
+}
+
+static void
+test_pubsub_msg_cancel_msgs(void *arg)
+{
+ dispatch_t *d = arg;
+
+ tt_int_op(0, OP_EQ, msg_received_msg1);
+ for (int i = 0; i < 100; ++i) {
+ SEND(msg1, "hello world");
+ }
+ tt_int_op(0, OP_EQ, msg_received_msg1); // hasn't actually arrived yet.
+
+ tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 10));
+ tt_int_op(10, OP_EQ, msg_received_msg1); // we got the message 10 times.
+
+ // At this point, the dispatcher will be freed with queued, undelivered
+ // messages.
+ done:
+ ;
+}
+
+struct alertfn_target {
+ dispatch_t *d;
+ channel_id_t ch;
+ int count;
+};
+static void
+alertfn_generic(dispatch_t *d, channel_id_t ch, void *arg)
+{
+ struct alertfn_target *t = arg;
+ tt_ptr_op(d, OP_EQ, t->d);
+ tt_int_op(ch, OP_EQ, t->ch);
+ ++t->count;
+ done:
+ ;
+}
+
+static void
+test_pubsub_msg_alertfns(void *arg)
+{
+ dispatch_t *d = arg;
+ struct alertfn_target ch1_a = { d, get_channel_id("main"), 0 };
+ struct alertfn_target ch2_a = { d, get_channel_id("other"), 0 };
+
+ tt_int_op(0, OP_EQ,
+ dispatch_set_alert_fn(d, get_channel_id("main"),
+ alertfn_generic, &ch1_a));
+ tt_int_op(0, OP_EQ,
+ dispatch_set_alert_fn(d, get_channel_id("other"),
+ alertfn_generic, &ch2_a));
+
+ SEND(msg3, "hello");
+ tt_int_op(ch1_a.count, OP_EQ, 1);
+ SEND(msg3, "world");
+ tt_int_op(ch1_a.count, OP_EQ, 1); // only the first message sends an alert
+ tt_int_op(ch2_a.count, OP_EQ, 0); // no alert for 'other'
+
+ SEND(msg4, "worse things happen in C");
+ tt_int_op(ch2_a.count, OP_EQ, 1);
+
+ // flush the first (main) channel...
+ tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 1000));
+ tt_int_op(6, OP_EQ, msg_received_msg3); // 3 subscribers, 2 instances.
+
+ // now that the main channel is flushed, sending another message on it
+ // starts another alert.
+ tt_int_op(ch1_a.count, OP_EQ, 1);
+ SEND(msg1, "plover");
+ tt_int_op(ch1_a.count, OP_EQ, 2);
+ tt_int_op(ch2_a.count, OP_EQ, 1);
+
+ done:
+ ;
+}
+
+/* try more than N_FAST_FNS hooks on msg5 */
+static void
+test_pubsub_msg_many_hooks(void *arg)
+{
+ dispatch_t *d = arg;
+ strings_received = smartlist_new();
+
+ tt_int_op(0, OP_EQ, msg_received_msg5);
+ SEND(msg5, "hello world");
+ tt_int_op(0, OP_EQ, msg_received_msg5);
+ tt_int_op(0, OP_EQ, smartlist_len(strings_received));
+
+ tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 100000));
+ tt_int_op(5, OP_EQ, msg_received_msg5);
+ tt_int_op(995, OP_EQ, smartlist_len(strings_received));
+
+ done:
+ SMARTLIST_FOREACH(strings_received, char *, s, tor_free(s));
+ smartlist_free(strings_received);
+}
+
+#define T(name) \
+ { #name, test_pubsub_msg_ ## name , TT_FORK, \
+ &dispatcher_setup, NULL }
+
+struct testcase_t pubsub_msg_tests[] = {
+ T(minimal),
+ T(send_to_stub),
+ T(cancel_msgs),
+ T(alertfns),
+ T(many_hooks),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_rebind.py b/src/test/test_rebind.py
index 30a587858f..6b72ece911 100644
--- a/src/test/test_rebind.py
+++ b/src/test/test_rebind.py
@@ -1,4 +1,7 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
import errno
import logging
@@ -22,9 +25,10 @@ def skip(msg):
def try_connecting_to_socksport():
socks_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- if socks_socket.connect_ex(('127.0.0.1', socks_port)):
+ e = socks_socket.connect_ex(('127.0.0.1', socks_port))
+ if e:
tor_process.terminate()
- fail('Cannot connect to SOCKSPort')
+ fail('Cannot connect to SOCKSPort: error ' + os.strerror(e))
socks_socket.close()
def wait_for_log(s):
@@ -112,7 +116,7 @@ tor_process = subprocess.Popen([tor_path,
if tor_process == None:
fail('ERROR: running tor failed')
-wait_for_log('Opened Control listener on')
+wait_for_log('Opened Control listener')
try_connecting_to_socksport()
diff --git a/src/test/test_rebind.sh b/src/test/test_rebind.sh
index ea2012957e..879008c1c1 100755
--- a/src/test/test_rebind.sh
+++ b/src/test/test_rebind.sh
@@ -1,24 +1,60 @@
#!/bin/sh
+umask 077
+set -e
set -x
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
UNAME_OS=$(uname -s | cut -d_ -f1)
if test "$UNAME_OS" = 'CYGWIN' || \
test "$UNAME_OS" = 'MSYS' || \
test "$UNAME_OS" = 'MINGW'; then
if test "$APPVEYOR" = 'True'; then
- echo "This test is disabled on Windows CI, as it requires firewall examptions. Skipping." >&2
+ echo "This test is disabled on Windows CI, as it requires firewall exemptions. Skipping." >&2
exit 77
fi
fi
-exitcode=0
+# find the tor binary
+if [ $# -ge 1 ]; then
+ TOR_BINARY="${1}"
+ shift
+else
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+if "${TOR_BINARY}" --list-modules | grep -q "relay: no"; then
+ echo "This test requires the relay module. Skipping." >&2
+ exit 77
+fi
tmpdir=
-clean () { test -n "$tmpdir" && test -d "$tmpdir" && rm -rf "$tmpdir" || :; }
+clean () {
+ if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then
+ rm -rf "$tmpdir"
+ fi
+}
+
trap clean EXIT HUP INT TERM
-tmpdir="`mktemp -d -t tor_rebind_test.XXXXXX`"
+tmpdir="$(mktemp -d -t tor_rebind_test.XXXXXX)"
if [ -z "$tmpdir" ]; then
echo >&2 mktemp failed
exit 2
@@ -27,6 +63,6 @@ elif [ ! -d "$tmpdir" ]; then
exit 3
fi
-"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/test_rebind.py" "${TESTING_TOR_BINARY}" "$tmpdir"
+"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/test_rebind.py" "${TOR_BINARY}" "$tmpdir"
exit $?
diff --git a/src/test/test_relay.c b/src/test/test_relay.c
index 0b7a7be332..8ed29b6282 100644
--- a/src/test/test_relay.c
+++ b/src/test/test_relay.c
@@ -1,60 +1,45 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITBUILD_PRIVATE
#define RELAY_PRIVATE
-#define REPHIST_PRIVATE
+#define BWHIST_PRIVATE
#include "core/or/or.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/channeltls.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/bwhist.h"
#include "core/or/relay.h"
-#include "feature/stats/rephist.h"
#include "lib/container/order.h"
+#include "lib/encoding/confline.h"
/* For init/free stuff */
#include "core/or/scheduler.h"
#include "core/or/cell_st.h"
#include "core/or/or_circuit_st.h"
+#define RESOLVE_ADDR_PRIVATE
+#include "feature/nodelist/dirlist.h"
+#include "feature/relay/relay_find_addr.h"
+#include "feature/relay/routermode.h"
+#include "feature/dirclient/dir_server_st.h"
+
+#define CONFIG_PRIVATE
+#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
+
/* Test suite stuff */
#include "test/test.h"
#include "test/fakechans.h"
-
-static or_circuit_t * new_fake_orcirc(channel_t *nchan, channel_t *pchan);
+#include "test/fakecircs.h"
static void test_relay_append_cell_to_circuit_queue(void *arg);
-static or_circuit_t *
-new_fake_orcirc(channel_t *nchan, channel_t *pchan)
+static int
+mock_server_mode_true(const or_options_t *options)
{
- or_circuit_t *orcirc = NULL;
- circuit_t *circ = NULL;
-
- orcirc = tor_malloc_zero(sizeof(*orcirc));
- circ = &(orcirc->base_);
- circ->magic = OR_CIRCUIT_MAGIC;
-
- circuit_set_n_circid_chan(circ, get_unique_circ_id_by_chan(nchan), nchan);
- cell_queue_init(&(circ->n_chan_cells));
-
- circ->n_hop = NULL;
- circ->streams_blocked_on_n_chan = 0;
- circ->streams_blocked_on_p_chan = 0;
- circ->n_delete_pending = 0;
- circ->p_delete_pending = 0;
- circ->received_destroy = 0;
- circ->state = CIRCUIT_STATE_OPEN;
- circ->purpose = CIRCUIT_PURPOSE_OR;
- circ->package_window = CIRCWINDOW_START_MAX;
- circ->deliver_window = CIRCWINDOW_START_MAX;
- circ->n_chan_create_cell = NULL;
-
- circuit_set_p_circid_chan(orcirc, get_unique_circ_id_by_chan(pchan), pchan);
- cell_queue_init(&(orcirc->p_chan_cells));
-
- return orcirc;
+ (void) options;
+ return 1;
}
static void
@@ -113,7 +98,7 @@ test_relay_close_circuit(void *arg)
tt_int_op(new_count, OP_EQ, old_count + 1);
/* Ensure our write totals are 0 */
- tt_u64_op(find_largest_max(write_array), OP_EQ, 0);
+ tt_u64_op(find_largest_max(write_array, 86400), OP_EQ, 0);
/* Mark the circuit for close */
circuit_mark_for_close(TO_CIRCUIT(orcirc), 0);
@@ -122,7 +107,7 @@ test_relay_close_circuit(void *arg)
advance_obs(write_array);
commit_max(write_array);
/* Check for two cells plus overhead */
- tt_u64_op(find_largest_max(write_array), OP_EQ,
+ tt_u64_op(find_largest_max(write_array, 86400), OP_EQ,
2*(get_cell_network_size(nchan->wide_circ_ids)
+TLS_PER_CELL_OVERHEAD));
@@ -145,7 +130,7 @@ test_relay_close_circuit(void *arg)
cell_queue_clear(&orcirc->base_.n_chan_cells);
cell_queue_clear(&orcirc->p_chan_cells);
}
- tor_free(orcirc);
+ free_fake_orcirc(orcirc);
free_fake_channel(nchan);
free_fake_channel(pchan);
UNMOCK(assert_circuit_ok);
@@ -218,17 +203,186 @@ test_relay_append_cell_to_circuit_queue(void *arg)
cell_queue_clear(&orcirc->base_.n_chan_cells);
cell_queue_clear(&orcirc->p_chan_cells);
}
- tor_free(orcirc);
+ free_fake_orcirc(orcirc);
free_fake_channel(nchan);
free_fake_channel(pchan);
return;
}
+static void
+test_suggested_address(void *arg)
+{
+ int ret;
+ const char *untrusted_id = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+ dir_server_t *ds = NULL;
+ tor_addr_t ipv4_addr, ipv6_addr, cache_addr;
+ tor_addr_t trusted_addr, untrusted_addr;
+ tor_addr_port_t trusted_ap_v6 = { .port = 443 };
+
+ (void) arg;
+
+ MOCK(server_mode, mock_server_mode_true);
+
+ /* Unstrusted relay source. */
+ ret = tor_addr_parse(&untrusted_addr, "8.8.8.8");
+ tt_int_op(ret, OP_EQ, AF_INET);
+
+ /* Add gabelmoo as a trusted directory authority. */
+ ret = tor_addr_parse(&trusted_addr, "[2001:638:a000:4140::ffff:189]");
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ tor_addr_copy(&trusted_ap_v6.addr, &trusted_addr);
+
+ ds = trusted_dir_server_new("gabelmoo", "131.188.40.189", 80, 443,
+ &trusted_ap_v6,
+ "F2044413DAC2E02E3D6BCF4735A19BCA1DE97281",
+ "ED03BB616EB2F60BEC80151114BB25CEF515B226",
+ V3_DIRINFO, 1.0);
+ tt_assert(ds);
+ dir_server_add(ds);
+
+ /* 1. Valid IPv4 from a trusted authority (gabelmoo). */
+ ret = tor_addr_parse(&ipv4_addr, "1.2.3.4");
+ relay_address_new_suggestion(&ipv4_addr, &ds->ipv4_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET, &cache_addr);
+ tt_assert(tor_addr_eq(&cache_addr, &ipv4_addr));
+ resolve_addr_reset_suggested(AF_INET);
+
+ /* 2. Valid IPv6 from a trusted authority (gabelmoo). */
+ ret = tor_addr_parse(&ipv6_addr, "[4242::4242]");
+ relay_address_new_suggestion(&ipv6_addr, &ds->ipv6_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET6, &cache_addr);
+ tt_assert(tor_addr_eq(&cache_addr, &ipv6_addr));
+ resolve_addr_reset_suggested(AF_INET6);
+
+ /* 3. Valid IPv4 but untrusted source. */
+ ret = tor_addr_parse(&ipv4_addr, "1.2.3.4");
+ relay_address_new_suggestion(&ipv4_addr, &untrusted_addr, untrusted_id);
+ resolved_addr_get_suggested(AF_INET, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ /* 4. Valid IPv6 but untrusted source. */
+ ret = tor_addr_parse(&ipv6_addr, "[4242::4242]");
+ relay_address_new_suggestion(&ipv6_addr, &untrusted_addr, untrusted_id);
+ resolved_addr_get_suggested(AF_INET6, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ /* 5. Internal IPv4 from a trusted authority (gabelmoo). */
+ ret = tor_addr_parse(&ipv4_addr, "127.0.0.1");
+ relay_address_new_suggestion(&ipv4_addr, &ds->ipv4_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ /* 6. Internal IPv6 from a trusted authority (gabelmoo). */
+ ret = tor_addr_parse(&ipv6_addr, "[::1]");
+ relay_address_new_suggestion(&ipv6_addr, &ds->ipv6_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET6, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ /* 7. IPv4 from a trusted authority (gabelmoo). */
+ relay_address_new_suggestion(&ds->ipv4_addr, &ds->ipv4_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ /* 8. IPv6 from a trusted authority (gabelmoo). */
+ relay_address_new_suggestion(&ds->ipv6_addr, &ds->ipv6_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET6, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ done:
+ dirlist_free_all();
+
+ UNMOCK(server_mode);
+}
+
+static void
+test_find_addr_to_publish(void *arg)
+{
+ int family;
+ bool ret;
+ tor_addr_t ipv4_addr, ipv6_addr, cache_addr;
+ or_options_t *options;
+
+ (void) arg;
+
+ options = options_new();
+ options_init(options);
+
+ /* Populate our resolved cache with a valid IPv4 and IPv6. */
+ family = tor_addr_parse(&ipv4_addr, "1.2.3.4");
+ tt_int_op(family, OP_EQ, AF_INET);
+ resolved_addr_set_last(&ipv4_addr, RESOLVED_ADDR_CONFIGURED, NULL);
+ resolved_addr_get_last(AF_INET, &cache_addr);
+ tt_assert(tor_addr_eq(&ipv4_addr, &cache_addr));
+
+ family = tor_addr_parse(&ipv6_addr, "[4242::4242]");
+ tt_int_op(family, OP_EQ, AF_INET6);
+ resolved_addr_set_last(&ipv6_addr, RESOLVED_ADDR_CONFIGURED, NULL);
+ resolved_addr_get_last(AF_INET6, &cache_addr);
+ tt_assert(tor_addr_eq(&ipv6_addr, &cache_addr));
+
+ /* Setup ORPort config. */
+ {
+ int n, w, r;
+ char *msg = NULL;
+
+ config_line_append(&options->ORPort_lines, "ORPort", "9001");
+
+ r = parse_ports(options, 0, &msg, &n, &w);
+ tt_int_op(r, OP_EQ, 0);
+ }
+
+ /* 1. Address located in the resolved cache. */
+ ret = relay_find_addr_to_publish(options, AF_INET,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(ret);
+ tt_assert(tor_addr_eq(&ipv4_addr, &cache_addr));
+
+ ret = relay_find_addr_to_publish(options, AF_INET6,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(ret);
+ tt_assert(tor_addr_eq(&ipv6_addr, &cache_addr));
+ resolved_addr_reset_last(AF_INET);
+ resolved_addr_reset_last(AF_INET6);
+
+ /* 2. No IP in the resolve cache, go to the suggested cache. We will ignore
+ * the find_my_address() code path because that is extensively tested in
+ * another unit tests. */
+ resolved_addr_set_suggested(&ipv4_addr);
+ ret = relay_find_addr_to_publish(options, AF_INET,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(ret);
+ tt_assert(tor_addr_eq(&ipv4_addr, &cache_addr));
+
+ resolved_addr_set_suggested(&ipv6_addr);
+ ret = relay_find_addr_to_publish(options, AF_INET6,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(ret);
+ tt_assert(tor_addr_eq(&ipv6_addr, &cache_addr));
+ resolve_addr_reset_suggested(AF_INET);
+ resolve_addr_reset_suggested(AF_INET6);
+
+ /* 3. No IP anywhere. */
+ ret = relay_find_addr_to_publish(options, AF_INET,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(!ret);
+ ret = relay_find_addr_to_publish(options, AF_INET6,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(!ret);
+
+ done:
+ or_options_free(options);
+}
+
struct testcase_t relay_tests[] = {
{ "append_cell_to_circuit_queue", test_relay_append_cell_to_circuit_queue,
TT_FORK, NULL, NULL },
{ "close_circ_rephist", test_relay_close_circuit,
TT_FORK, NULL, NULL },
+ { "suggested_address", test_suggested_address,
+ TT_FORK, NULL, NULL },
+ { "find_addr_to_publish", test_find_addr_to_publish,
+ TT_FORK, NULL, NULL },
+
END_OF_TESTCASES
};
diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c
index 0623583511..6f5bc7e770 100644
--- a/src/test/test_relaycell.c
+++ b/src/test/test_relaycell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for handling different kinds of relay cell */
@@ -17,6 +17,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/connection_edge.h"
+#include "core/or/sendme.h"
#include "core/or/relay.h"
#include "test/test.h"
#include "test/log_test_helpers.h"
@@ -29,7 +30,6 @@
#include "core/or/half_edge_st.h"
#include "feature/client/circpathbias.h"
-#include "core/or/connection_edge.h"
static int srm_ncalls;
static entry_connection_t *srm_conn;
@@ -220,7 +220,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
int sendme_cells = (STREAMWINDOW_START-edgeconn->package_window)
/STREAMWINDOW_INCREMENT;
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
connection_edge_reached_eof(edgeconn);
/* Data cell not in the half-opened list */
@@ -272,7 +271,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* DATA cells up to limit */
while (data_cells > 0) {
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -283,7 +281,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
data_cells--;
}
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -295,7 +292,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* SENDME cells up to limit */
while (sendme_cells > 0) {
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -306,7 +302,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
sendme_cells--;
}
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -317,7 +312,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* Only one END cell */
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -327,7 +321,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
ASSERT_COUNTED_BW();
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -339,7 +332,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
edgeconn = ENTRY_TO_EDGE_CONN(entryconn3);
edgeconn->base_.state = AP_CONN_STATE_OPEN;
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
/* sendme cell on open entryconn with full window */
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
int ret =
@@ -350,7 +342,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* connected cell on a after EOF */
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT;
connection_edge_reached_eof(edgeconn);
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234");
@@ -362,7 +353,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
ASSERT_COUNTED_BW();
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -373,7 +363,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* DATA and SENDME after END cell */
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -383,7 +372,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
ASSERT_COUNTED_BW();
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
ret =
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
@@ -392,7 +380,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
ASSERT_UNCOUNTED_BW();
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -407,11 +394,9 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
edgeconn->base_.state = AP_CONN_STATE_RESOLVE_WAIT;
edgeconn->on_circuit = TO_CIRCUIT(circ);
ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0;
connection_edge_reached_eof(edgeconn);
ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED,
"\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
@@ -422,7 +407,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
ASSERT_COUNTED_BW();
ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED,
"\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
@@ -431,7 +415,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* Data not counted after resolved */
ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -442,7 +425,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* End not counted after resolved */
ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -509,7 +491,7 @@ subtest_halfstream_insertremove(int num)
entryconn = fake_entry_conn(circ, 23);
edgeconn = ENTRY_TO_EDGE_CONN(entryconn);
- /* Explicity test all operations on an absent stream list */
+ /* Explicitly test all operations on an absent stream list */
tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
23), OP_EQ, 0);
tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
@@ -588,7 +570,7 @@ subtest_halfstream_insertremove(int num)
}
tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 0);
- /* Explicity test all operations on an empty stream list */
+ /* Explicitly test all operations on an empty stream list */
tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
23), OP_EQ, 0);
tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
@@ -660,7 +642,6 @@ test_halfstream_wrap(void *arg)
/* Insert an opened stream on the circ with that id */
ENTRY_TO_CONN(entryconn)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0;
edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT;
circ->p_streams = edgeconn;
@@ -784,14 +765,12 @@ test_circbw_relay(void *arg)
/* Sendme on valid stream: counted */
edgeconn->package_window -= STREAMWINDOW_INCREMENT;
- ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0;
PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
circ->cpath);
ASSERT_COUNTED_BW();
/* Sendme on valid stream with full window: not counted */
- ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0;
PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
edgeconn->package_window = STREAMWINDOW_START;
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
@@ -799,7 +778,6 @@ test_circbw_relay(void *arg)
ASSERT_UNCOUNTED_BW();
/* Sendme on unknown stream: not counted */
- ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0;
PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
circ->cpath);
@@ -812,7 +790,11 @@ test_circbw_relay(void *arg)
ASSERT_UNCOUNTED_BW();
/* Sendme on circuit with non-full window: counted */
- PACK_CELL(0, RELAY_COMMAND_SENDME, "Data1234");
+ PACK_CELL(0, RELAY_COMMAND_SENDME, "");
+ /* Recording a cell, the window is updated after decryption so off by one in
+ * order to record and then we process it with the proper window. */
+ circ->cpath->package_window = 901;
+ sendme_record_cell_digest_on_circ(TO_CIRCUIT(circ), circ->cpath);
circ->cpath->package_window = 900;
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
circ->cpath);
diff --git a/src/test/test_relaycrypt.c b/src/test/test_relaycrypt.c
index fe6889e521..737c243e2d 100644
--- a/src/test/test_relaycrypt.c
+++ b/src/test/test_relaycrypt.c
@@ -1,8 +1,10 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#define CRYPT_PATH_PRIVATE
+
#include "core/or/or.h"
#include "core/or/circuitbuild.h"
#define CIRCUITLIST_PRIVATE
@@ -10,7 +12,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "core/or/relay.h"
#include "core/crypto/relay_crypto.h"
-
+#include "core/or/crypt_path.h"
#include "core/or/cell_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
@@ -49,10 +51,10 @@ testing_circuitset_setup(const struct testcase_t *testcase)
cs->origin_circ->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;
for (i=0; i<3; ++i) {
crypt_path_t *hop = tor_malloc_zero(sizeof(*hop));
- relay_crypto_init(&hop->crypto, KEY_MATERIAL[i], sizeof(KEY_MATERIAL[i]),
- 0, 0);
+ relay_crypto_init(&hop->pvt_crypto, KEY_MATERIAL[i],
+ sizeof(KEY_MATERIAL[i]), 0, 0);
hop->state = CPATH_STATE_OPEN;
- onion_append_to_cpath(&cs->origin_circ->cpath, hop);
+ cpath_extend_linked_list(&cs->origin_circ->cpath, hop);
tt_ptr_op(hop, OP_EQ, cs->origin_circ->cpath->prev);
}
diff --git a/src/test/test_rendcache.c b/src/test/test_rendcache.c
index 8b0e2df485..06167635c1 100644
--- a/src/test/test_rendcache.c
+++ b/src/test/test_rendcache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -21,8 +21,6 @@
#include "test/rend_test_helpers.h"
#include "test/log_test_helpers.h"
-#define NS_MODULE rend_cache
-
static const int RECENT_TIME = -10;
static const int TIME_IN_THE_PAST = -(REND_CACHE_MAX_AGE + \
REND_CACHE_MAX_SKEW + 60);
@@ -369,13 +367,12 @@ test_rend_cache_store_v2_desc_as_client_with_different_time(void *data)
rend_data_free(mock_rend_query);
}
-#define NS_SUBMODULE lookup_v2_desc_as_dir
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+static const routerinfo_t *rcache_lookup_v2_as_dir_get_my_routerinfo(void);
static routerinfo_t *mock_routerinfo;
static const routerinfo_t *
-NS(router_get_my_routerinfo)(void)
+rcache_lookup_v2_as_dir_get_my_routerinfo(void)
{
if (!mock_routerinfo) {
mock_routerinfo = tor_malloc(sizeof(routerinfo_t));
@@ -395,7 +392,8 @@ test_rend_cache_lookup_v2_desc_as_dir(void *data)
(void)data;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ rcache_lookup_v2_as_dir_get_my_routerinfo);
rend_cache_init();
@@ -418,20 +416,17 @@ test_rend_cache_lookup_v2_desc_as_dir(void *data)
tt_assert(ret_desc);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
tor_free(mock_routerinfo);
rend_cache_free_all();
rend_encoded_v2_service_descriptor_free(desc_holder);
tor_free(service_id);
}
-#undef NS_SUBMODULE
-
-#define NS_SUBMODULE store_v2_desc_as_dir
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+static const routerinfo_t *rcache_store_v2_as_dir_get_my_routerinfo(void);
static const routerinfo_t *
-NS(router_get_my_routerinfo)(void)
+rcache_store_v2_as_dir_get_my_routerinfo(void)
{
return mock_routerinfo;
}
@@ -444,7 +439,8 @@ test_rend_cache_store_v2_desc_as_dir(void *data)
rend_encoded_v2_service_descriptor_t *desc_holder = NULL;
char *service_id = NULL;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ rcache_store_v2_as_dir_get_my_routerinfo);
rend_cache_init();
@@ -485,7 +481,7 @@ test_rend_cache_store_v2_desc_as_dir(void *data)
tt_int_op(ret, OP_EQ, 0);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
rend_encoded_v2_service_descriptor_free(desc_holder);
tor_free(service_id);
rend_cache_free_all();
@@ -505,7 +501,8 @@ test_rend_cache_store_v2_desc_as_dir_with_different_time(void *data)
rend_encoded_v2_service_descriptor_t *desc_holder_newer;
rend_encoded_v2_service_descriptor_t *desc_holder_older;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ rcache_store_v2_as_dir_get_my_routerinfo);
rend_cache_init();
@@ -543,7 +540,7 @@ test_rend_cache_store_v2_desc_as_dir_with_different_time(void *data)
tt_int_op(ret, OP_EQ, 0);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
rend_cache_free_all();
rend_service_descriptor_free(generated);
tor_free(service_id);
@@ -568,7 +565,8 @@ test_rend_cache_store_v2_desc_as_dir_with_different_content(void *data)
rend_encoded_v2_service_descriptor_t *desc_holder_one = NULL;
rend_encoded_v2_service_descriptor_t *desc_holder_two = NULL;
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(router_get_my_routerinfo,
+ rcache_store_v2_as_dir_get_my_routerinfo);
rend_cache_init();
@@ -602,7 +600,7 @@ test_rend_cache_store_v2_desc_as_dir_with_different_content(void *data)
tt_int_op(ret, OP_EQ, 0);
done:
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(router_get_my_routerinfo);
rend_cache_free_all();
rend_service_descriptor_free(generated);
tor_free(service_id);
@@ -613,8 +611,6 @@ test_rend_cache_store_v2_desc_as_dir_with_different_content(void *data)
rend_encoded_v2_service_descriptor_free(desc_holder_two);
}
-#undef NS_SUBMODULE
-
static void
test_rend_cache_init(void *data)
{
@@ -1077,8 +1073,6 @@ test_rend_cache_intro_failure_note(void *data)
rend_cache_free_all();
}
-#define NS_SUBMODULE clean_v2_descs_as_dir
-
static void
test_rend_cache_clean_v2_descs_as_dir(void *data)
{
@@ -1120,8 +1114,6 @@ test_rend_cache_clean_v2_descs_as_dir(void *data)
rend_cache_free_all();
}
-#undef NS_SUBMODULE
-
static void
test_rend_cache_entry_allocation(void *data)
{
diff --git a/src/test/test_replay.c b/src/test/test_replay.c
index 28a508bf4d..1487b0a29d 100644
--- a/src/test/test_replay.c
+++ b/src/test/test_replay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Tor Project, Inc. */
+/* Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define REPLAYCACHE_PRIVATE
diff --git a/src/test/test_rng.c b/src/test/test_rng.c
new file mode 100644
index 0000000000..ebaffb74f5
--- /dev/null
+++ b/src/test/test_rng.c
@@ -0,0 +1,59 @@
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/*
+ * Example usage:
+ *
+ * ./src/test/test-rng --emit | dieharder -g 200 -a
+ *
+ * Remember, dieharder can tell you that your RNG is completely broken, but if
+ * your RNG is not _completely_ broken, dieharder cannot tell you whether your
+ * RNG is actually secure.
+ */
+
+#include "orconfig.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "lib/crypt_ops/crypto_rand.h"
+
+int
+main(int argc, char **argv)
+{
+ uint8_t buf[0x123];
+
+ if (argc != 2 || strcmp(argv[1], "--emit")) {
+ fprintf(stderr, "If you want me to fill stdout with a bunch of random "
+ "bytes, you need to say --emit.\n");
+ return 1;
+ }
+
+ if (crypto_seed_rng() < 0) {
+ fprintf(stderr, "Can't seed RNG.\n");
+ return 1;
+ }
+
+#if 0
+ while (1) {
+ crypto_rand(buf, sizeof(buf));
+ if (write(1 /*stdout*/, buf, sizeof(buf)) != sizeof(buf)) {
+ fprintf(stderr, "write() failed: %s\n", strerror(errno));
+ return 1;
+ }
+ }
+#endif /* 0 */
+
+ crypto_fast_rng_t *rng = crypto_fast_rng_new();
+ while (1) {
+ crypto_fast_rng_getbytes(rng, buf, sizeof(buf));
+ if (write(1 /*stdout*/, buf, sizeof(buf)) != sizeof(buf)) {
+ fprintf(stderr, "write() failed: %s\n", strerror(errno));
+ return 1;
+ }
+ }
+}
diff --git a/src/test/test_router.c b/src/test/test_router.c
index e0d3adfdbd..895178f788 100644
--- a/src/test/test_router.c
+++ b/src/test/test_router.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* Copyright (c) 2017, isis agora lovecruft */
/* See LICENSE for licensing information */
@@ -9,15 +9,23 @@
#define CONFIG_PRIVATE
#define CONNECTION_PRIVATE
+#define ROUTER_PRIVATE
+
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/connection.h"
#include "feature/hibernate/hibernate.h"
+#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/networkstatus_st.h"
+#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerlist.h"
+#include "feature/nodelist/routerstatus_st.h"
+#include "feature/nodelist/torcert.h"
#include "feature/relay/router.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/bwhist.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/encoding/confline.h"
@@ -28,43 +36,34 @@
#include "test/test.h"
#include "test/log_test_helpers.h"
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
-
-static routerinfo_t* mock_routerinfo;
-
-static const routerinfo_t*
-NS(router_get_my_routerinfo)(void)
+static routerinfo_t *
+rtr_tests_gen_routerinfo(crypto_pk_t *ident_key, crypto_pk_t *tap_key)
{
- crypto_pk_t* ident_key;
- crypto_pk_t* tap_key;
time_t now;
- if (!mock_routerinfo) {
- /* Mock the published timestamp, otherwise router_dump_router_to_string()
- * will poop its pants. */
- time(&now);
-
- /* We'll need keys, or router_dump_router_to_string() would return NULL. */
- ident_key = pk_generate(0);
- tap_key = pk_generate(0);
-
- tor_assert(ident_key != NULL);
- tor_assert(tap_key != NULL);
-
- mock_routerinfo = tor_malloc_zero(sizeof(routerinfo_t));
- mock_routerinfo->nickname = tor_strdup("ConlonNancarrow");
- mock_routerinfo->addr = 123456789;
- mock_routerinfo->or_port = 443;
- mock_routerinfo->platform = tor_strdup("unittest");
- mock_routerinfo->cache_info.published_on = now;
- mock_routerinfo->identity_pkey = crypto_pk_dup_key(ident_key);
- router_set_rsa_onion_pkey(tap_key, &mock_routerinfo->onion_pkey,
- &mock_routerinfo->onion_pkey_len);
- mock_routerinfo->bandwidthrate = 9001;
- mock_routerinfo->bandwidthburst = 9002;
- crypto_pk_free(ident_key);
- crypto_pk_free(tap_key);
- }
+ routerinfo_t *mock_routerinfo;
+
+ /* Mock the published timestamp, otherwise router_dump_router_to_string()
+ * will poop its pants. */
+ time(&now);
+
+ /* We'll need keys, or router_dump_router_to_string() would return NULL. */
+ tor_assert(ident_key != NULL);
+ tor_assert(tap_key != NULL);
+
+ mock_routerinfo = tor_malloc_zero(sizeof(routerinfo_t));
+ mock_routerinfo->nickname = tor_strdup("ConlonNancarrow");
+ tor_addr_from_ipv4h(&mock_routerinfo->ipv4_addr, 123456789);
+ mock_routerinfo->ipv4_orport = 443;
+ mock_routerinfo->platform = tor_strdup("unittest");
+ mock_routerinfo->cache_info.published_on = now;
+ mock_routerinfo->identity_pkey = crypto_pk_dup_key(ident_key);
+ mock_routerinfo->protocol_list =
+ tor_strdup("Cons=1-2 Desc=1-2 DirCache=1-2");
+ router_set_rsa_onion_pkey(tap_key, &mock_routerinfo->onion_pkey,
+ &mock_routerinfo->onion_pkey_len);
+ mock_routerinfo->bandwidthrate = 9001;
+ mock_routerinfo->bandwidthburst = 9002;
return mock_routerinfo;
}
@@ -79,44 +78,57 @@ test_router_dump_router_to_string_no_bridge_distribution_method(void *arg)
routerinfo_t* router = NULL;
curve25519_keypair_t ntor_keypair;
ed25519_keypair_t signing_keypair;
+ ed25519_keypair_t identity_keypair;
char* desc = NULL;
char* found = NULL;
(void)arg;
-
- NS_MOCK(router_get_my_routerinfo);
+ crypto_pk_t *ident_key = pk_generate(0);
+ crypto_pk_t *tap_key = pk_generate(0);
options->ORPort_set = 1;
options->BridgeRelay = 1;
/* Generate keys which router_dump_router_to_string() expects to exist. */
- tt_int_op(0, ==, curve25519_keypair_generate(&ntor_keypair, 0));
- tt_int_op(0, ==, ed25519_keypair_generate(&signing_keypair, 0));
+ tt_int_op(0, OP_EQ, curve25519_keypair_generate(&ntor_keypair, 0));
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&signing_keypair, 0));
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&identity_keypair, 0));
/* Set up part of our routerinfo_t so that we don't trigger any other
* assertions in router_dump_router_to_string(). */
- router = (routerinfo_t*)router_get_my_routerinfo();
- tt_ptr_op(router, !=, NULL);
-
+ router = rtr_tests_gen_routerinfo(ident_key, tap_key);
+ tt_ptr_op(router, OP_NE, NULL);
+
+ router->cache_info.signing_key_cert =
+ tor_cert_create_ed25519(&identity_keypair,
+ CERT_TYPE_ID_SIGNING,
+ &signing_keypair.pubkey,
+ time(NULL),
+ 86400,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+
+ /* The real router_get_my_routerinfo() looks up onion_curve25519_pkey using
+ * get_current_curve25519_keypair(), but we don't initialise static data in
+ * this test. */
router->onion_curve25519_pkey = &ntor_keypair.pubkey;
/* Generate our server descriptor and ensure that the substring
* "bridge-distribution-request any" occurs somewhere within it. */
- crypto_pk_t *onion_pkey = router_get_rsa_onion_pkey(router->onion_pkey,
- router->onion_pkey_len);
desc = router_dump_router_to_string(router,
- router->identity_pkey,
- onion_pkey,
+ ident_key,
+ tap_key,
&ntor_keypair,
&signing_keypair);
- crypto_pk_free(onion_pkey);
- tt_ptr_op(desc, !=, NULL);
+ tt_ptr_op(desc, OP_NE, NULL);
found = strstr(desc, needle);
- tt_ptr_op(found, !=, NULL);
+ tt_ptr_op(found, OP_NE, NULL);
done:
- NS_UNMOCK(router_get_my_routerinfo);
-
+ if (router)
+ router->onion_curve25519_pkey = NULL; // avoid double-free
+ routerinfo_free(router);
tor_free(desc);
+ crypto_pk_free(ident_key);
+ crypto_pk_free(tap_key);
}
static routerinfo_t *mock_router_get_my_routerinfo_result = NULL;
@@ -214,13 +226,13 @@ test_router_check_descriptor_bandwidth_changed(void *arg)
/* When uptime is less than 24h and bandwidthcapacity does not change
* Uptime: 10800, last_changed: x, Previous bw: 10000, Current bw: 20001 */
- MOCK(rep_hist_bandwidth_assess, mock_rep_hist_bandwidth_assess);
+ MOCK(bwhist_bandwidth_assess, mock_rep_hist_bandwidth_assess);
setup_full_capture_of_logs(LOG_INFO);
check_descriptor_bandwidth_changed(time(NULL) + 6*60*60 + 1);
expect_log_msg_containing(
"Measured bandwidth has changed; rebuilding descriptor.");
UNMOCK(get_uptime);
- UNMOCK(rep_hist_bandwidth_assess);
+ UNMOCK(bwhist_bandwidth_assess);
teardown_capture_of_logs();
/* When uptime is more than 24h */
@@ -237,6 +249,247 @@ test_router_check_descriptor_bandwidth_changed(void *arg)
UNMOCK(we_are_hibernating);
}
+static networkstatus_t *mock_ns = NULL;
+static networkstatus_t *
+mock_networkstatus_get_live_consensus(time_t now)
+{
+ (void)now;
+ return mock_ns;
+}
+
+static routerstatus_t *mock_rs = NULL;
+static const routerstatus_t *
+mock_networkstatus_vote_find_entry(networkstatus_t *ns, const char *digest)
+{
+ (void)ns;
+ (void)digest;
+ return mock_rs;
+}
+
+static void
+test_router_mark_if_too_old(void *arg)
+{
+ (void)arg;
+ time_t now = approx_time();
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+ MOCK(networkstatus_vote_find_entry, mock_networkstatus_vote_find_entry);
+
+ routerstatus_t rs;
+ networkstatus_t ns;
+ memset(&rs, 0, sizeof(rs));
+ memset(&ns, 0, sizeof(ns));
+ mock_ns = &ns;
+ mock_ns->valid_after = now-3600;
+ mock_rs = &rs;
+ mock_rs->published_on = now - 10;
+
+ // no reason to mark this time.
+ desc_clean_since = now-10;
+ desc_dirty_reason = NULL;
+ mark_my_descriptor_dirty_if_too_old(now);
+ tt_i64_op(desc_clean_since, OP_EQ, now-10);
+
+ // Doesn't appear in consensus? Still don't mark it.
+ mock_ns = NULL;
+ mark_my_descriptor_dirty_if_too_old(now);
+ tt_i64_op(desc_clean_since, OP_EQ, now-10);
+ mock_ns = &ns;
+
+ // No new descriptor in a long time? Mark it.
+ desc_clean_since = now - 3600 * 96;
+ mark_my_descriptor_dirty_if_too_old(now);
+ tt_i64_op(desc_clean_since, OP_EQ, 0);
+ tt_str_op(desc_dirty_reason, OP_EQ, "time for new descriptor");
+
+ // Version in consensus published a long time ago? We won't mark it
+ // if it's been clean for only a short time.
+ desc_clean_since = now - 10;
+ desc_dirty_reason = NULL;
+ mock_rs->published_on = now - 3600 * 96;
+ mark_my_descriptor_dirty_if_too_old(now);
+ tt_i64_op(desc_clean_since, OP_EQ, now - 10);
+
+ // ... but if it's been clean a while, we mark.
+ desc_clean_since = now - 2 * 3600;
+ mark_my_descriptor_dirty_if_too_old(now);
+ tt_i64_op(desc_clean_since, OP_EQ, 0);
+ tt_str_op(desc_dirty_reason, OP_EQ,
+ "version listed in consensus is quite old");
+
+ // same deal if we're marked stale.
+ desc_clean_since = now - 2 * 3600;
+ desc_dirty_reason = NULL;
+ mock_rs->published_on = now - 10;
+ mock_rs->is_staledesc = 1;
+ mark_my_descriptor_dirty_if_too_old(now);
+ tt_i64_op(desc_clean_since, OP_EQ, 0);
+ tt_str_op(desc_dirty_reason, OP_EQ,
+ "listed as stale in consensus");
+
+ // same deal if we're absent from the consensus.
+ desc_clean_since = now - 2 * 3600;
+ desc_dirty_reason = NULL;
+ mock_rs = NULL;
+ mark_my_descriptor_dirty_if_too_old(now);
+ tt_i64_op(desc_clean_since, OP_EQ, 0);
+ tt_str_op(desc_dirty_reason, OP_EQ,
+ "not listed in consensus");
+
+ done:
+ UNMOCK(networkstatus_get_live_consensus);
+ UNMOCK(networkstatus_vote_find_entry);
+}
+
+static node_t fake_node;
+static const node_t *
+mock_node_get_by_nickname(const char *name, unsigned flags)
+{
+ (void)flags;
+ if (!strcasecmp(name, "crumpet"))
+ return &fake_node;
+ else
+ return NULL;
+}
+
+static void
+test_router_get_my_family(void *arg)
+{
+ (void)arg;
+ or_options_t *options = options_new();
+ smartlist_t *sl = NULL;
+ char *join = NULL;
+ // Overwrite the result of router_get_my_identity_digest(). This
+ // happens to be okay, but only for testing.
+ set_server_identity_key_digest_testing(
+ (const uint8_t*)"holeinthebottomofthe");
+
+ setup_capture_of_logs(LOG_WARN);
+
+ // No family listed -- so there's no list.
+ sl = get_my_declared_family(options);
+ tt_ptr_op(sl, OP_EQ, NULL);
+ expect_no_log_entry();
+
+#define CLEAR() do { \
+ if (sl) { \
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); \
+ smartlist_free(sl); \
+ } \
+ tor_free(join); \
+ mock_clean_saved_logs(); \
+ } while (0)
+
+ // Add a single nice friendly hex member. This should be enough
+ // to have our own ID added.
+ tt_ptr_op(options->MyFamily, OP_EQ, NULL);
+ config_line_append(&options->MyFamily, "MyFamily",
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+
+ sl = get_my_declared_family(options);
+ tt_ptr_op(sl, OP_NE, NULL);
+ tt_int_op(smartlist_len(sl), OP_EQ, 2);
+ join = smartlist_join_strings(sl, " ", 0, NULL);
+ tt_str_op(join, OP_EQ,
+ "$686F6C65696E746865626F74746F6D6F66746865 "
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+ expect_no_log_entry();
+ CLEAR();
+
+ // Add a hex member with a ~. The ~ part should get removed.
+ config_line_append(&options->MyFamily, "MyFamily",
+ "$0123456789abcdef0123456789abcdef01234567~Muffin");
+ sl = get_my_declared_family(options);
+ tt_ptr_op(sl, OP_NE, NULL);
+ tt_int_op(smartlist_len(sl), OP_EQ, 3);
+ join = smartlist_join_strings(sl, " ", 0, NULL);
+ tt_str_op(join, OP_EQ,
+ "$0123456789ABCDEF0123456789ABCDEF01234567 "
+ "$686F6C65696E746865626F74746F6D6F66746865 "
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+ expect_no_log_entry();
+ CLEAR();
+
+ // Nickname lookup will fail, so a nickname will appear verbatim.
+ config_line_append(&options->MyFamily, "MyFamily",
+ "BAGEL");
+ sl = get_my_declared_family(options);
+ tt_ptr_op(sl, OP_NE, NULL);
+ tt_int_op(smartlist_len(sl), OP_EQ, 4);
+ join = smartlist_join_strings(sl, " ", 0, NULL);
+ tt_str_op(join, OP_EQ,
+ "$0123456789ABCDEF0123456789ABCDEF01234567 "
+ "$686F6C65696E746865626F74746F6D6F66746865 "
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
+ "bagel");
+ expect_single_log_msg_containing(
+ "There is a router named \"BAGEL\" in my declared family, but "
+ "I have no descriptor for it.");
+ CLEAR();
+
+ // A bogus digest should fail entirely.
+ config_line_append(&options->MyFamily, "MyFamily",
+ "$painauchocolat");
+ sl = get_my_declared_family(options);
+ tt_ptr_op(sl, OP_NE, NULL);
+ tt_int_op(smartlist_len(sl), OP_EQ, 4);
+ join = smartlist_join_strings(sl, " ", 0, NULL);
+ tt_str_op(join, OP_EQ,
+ "$0123456789ABCDEF0123456789ABCDEF01234567 "
+ "$686F6C65696E746865626F74746F6D6F66746865 "
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
+ "bagel");
+ // "BAGEL" is still there, but it won't make a warning, because we already
+ // warned about it.
+ expect_single_log_msg_containing(
+ "There is a router named \"$painauchocolat\" in my declared "
+ "family, but that isn't a legal digest or nickname. Skipping it.");
+ CLEAR();
+
+ // Let's introduce a node we can look up by nickname
+ memset(&fake_node, 0, sizeof(fake_node));
+ memcpy(fake_node.identity, "whydoyouasknonononon", DIGEST_LEN);
+ MOCK(node_get_by_nickname, mock_node_get_by_nickname);
+
+ config_line_append(&options->MyFamily, "MyFamily",
+ "CRUmpeT");
+ sl = get_my_declared_family(options);
+ tt_ptr_op(sl, OP_NE, NULL);
+ tt_int_op(smartlist_len(sl), OP_EQ, 5);
+ join = smartlist_join_strings(sl, " ", 0, NULL);
+ tt_str_op(join, OP_EQ,
+ "$0123456789ABCDEF0123456789ABCDEF01234567 "
+ "$686F6C65696E746865626F74746F6D6F66746865 "
+ "$776879646F796F7561736B6E6F6E6F6E6F6E6F6E "
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
+ "bagel");
+ // "BAGEL" is still there, but it won't make a warning, because we already
+ // warned about it. Some with "$painauchocolat".
+ expect_single_log_msg_containing(
+ "There is a router named \"CRUmpeT\" in my declared "
+ "family, but it wasn't listed by digest. Please consider saying "
+ "$776879646F796F7561736B6E6F6E6F6E6F6E6F6E instead, if that's "
+ "what you meant.");
+ CLEAR();
+ UNMOCK(node_get_by_nickname);
+
+ // Try a singleton list containing only us: It should give us NULL.
+ config_free_lines(options->MyFamily);
+ config_line_append(&options->MyFamily, "MyFamily",
+ "$686F6C65696E746865626F74746F6D6F66746865");
+ sl = get_my_declared_family(options);
+ tt_ptr_op(sl, OP_EQ, NULL);
+ expect_no_log_entry();
+
+ done:
+ or_options_free(options);
+ teardown_capture_of_logs();
+ CLEAR();
+ UNMOCK(node_get_by_nickname);
+
+#undef CLEAR
+}
+
static smartlist_t *fake_connection_array = NULL;
static smartlist_t *
mock_get_connection_array(void)
@@ -254,13 +507,12 @@ test_router_get_advertised_or_port(void *arg)
listener_connection_t *listener = NULL;
tor_addr_port_t ipv6;
- // Test one failing case of router_get_advertised_ipv6_or_ap().
- router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ // Test one failing case of routerconf_find_ipv6_or_ap().
+ routerconf_find_ipv6_or_ap(opts, &ipv6);
tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
- // And one failing case of router_get_advertised_or_port().
- tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
- tt_int_op(0, OP_EQ, router_get_advertised_or_port(opts));
+ // And one failing case of routerconf_find_or_port().
+ tt_int_op(0, OP_EQ, routerconf_find_or_port(opts, AF_INET));
// Set up a couple of configured ports.
config_line_append(&opts->ORPort_lines, "ORPort", "[1234::5678]:auto");
@@ -269,13 +521,12 @@ test_router_get_advertised_or_port(void *arg)
tt_assert(r == 0);
// There are no listeners, so the "auto" case will turn up no results.
- tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
- router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_int_op(0, OP_EQ, routerconf_find_or_port(opts, AF_INET6));
+ routerconf_find_ipv6_or_ap(opts, &ipv6);
tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
// This will return the matching value from the configured port.
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts));
+ tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET));
// Now set up a dummy listener.
MOCK(get_connection_array, mock_get_connection_array);
@@ -285,16 +536,15 @@ test_router_get_advertised_or_port(void *arg)
smartlist_add(fake_connection_array, TO_CONN(listener));
// We should get a port this time.
- tt_int_op(54321, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+ tt_int_op(54321, OP_EQ, routerconf_find_or_port(opts, AF_INET6));
- // Test one succeeding case of router_get_advertised_ipv6_or_ap().
- router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ // Test one succeeding case of routerconf_find_ipv6_or_ap().
+ routerconf_find_ipv6_or_ap(opts, &ipv6);
tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ,
"[1234::5678]:54321");
// This will return the matching value from the configured port.
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts));
+ tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET));
done:
or_options_free(opts);
@@ -320,28 +570,26 @@ test_router_get_advertised_or_port_localhost(void *arg)
tt_assert(r == 0);
// We should refuse to advertise them, since we have default dirauths.
- router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ routerconf_find_ipv6_or_ap(opts, &ipv6);
tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
// But the lower-level function should still report the correct value
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+ tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET6));
// The IPv4 checks are done in resolve_my_address(), which doesn't use
// ORPorts so we can't test them here. (See #33681.) Both these lower-level
// functions should still report the correct value.
- tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
- tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts));
+ tt_int_op(8888, OP_EQ, routerconf_find_or_port(opts, AF_INET));
// Now try with a fake authority set up.
config_line_append(&opts->DirAuthorities, "DirAuthority",
"127.0.0.1:1066 "
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
- router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET6));
+ routerconf_find_ipv6_or_ap(opts, &ipv6);
tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::1]:9999");
- tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
- tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts));
+ tt_int_op(8888, OP_EQ, routerconf_find_or_port(opts, AF_INET));
done:
or_options_free(opts);
@@ -354,6 +602,8 @@ test_router_get_advertised_or_port_localhost(void *arg)
struct testcase_t router_tests[] = {
ROUTER_TEST(check_descriptor_bandwidth_changed, TT_FORK),
ROUTER_TEST(dump_router_to_string_no_bridge_distribution_method, TT_FORK),
+ ROUTER_TEST(mark_if_too_old, TT_FORK),
+ ROUTER_TEST(get_my_family, TT_FORK),
ROUTER_TEST(get_advertised_or_port, TT_FORK),
ROUTER_TEST(get_advertised_or_port_localhost, TT_FORK),
END_OF_TESTCASES
diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c
index 727fa5660f..e5314046b9 100644
--- a/src/test/test_routerkeys.c
+++ b/src/test/test_routerkeys.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -51,7 +51,7 @@ test_routerkeys_write_fingerprint(void *arg)
tt_int_op(crypto_pk_cmp_keys(get_server_identity_key(),key),OP_EQ,0);
/* Write fingerprint file */
- tt_int_op(0, OP_EQ, router_write_fingerprint(0));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(0, 0));
cp = read_file_to_str(get_fname("write_fingerprint/fingerprint"),
0, NULL);
crypto_pk_get_fingerprint(key, fp, 0);
@@ -61,7 +61,7 @@ test_routerkeys_write_fingerprint(void *arg)
tor_free(cp2);
/* Write hashed-fingerprint file */
- tt_int_op(0, OP_EQ, router_write_fingerprint(1));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(1, 0));
cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
0, NULL);
crypto_pk_get_hashed_fingerprint(key, fp);
@@ -73,7 +73,7 @@ test_routerkeys_write_fingerprint(void *arg)
/* Replace outdated file */
write_str_to_file(get_fname("write_fingerprint/hashed-fingerprint"),
"junk goes here", 0);
- tt_int_op(0, OP_EQ, router_write_fingerprint(1));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(1, 0));
cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
0, NULL);
crypto_pk_get_hashed_fingerprint(key, fp);
@@ -90,6 +90,51 @@ test_routerkeys_write_fingerprint(void *arg)
}
static void
+test_routerkeys_write_ed25519_identity(void *arg)
+{
+ crypto_pk_t *key = pk_generate(2);
+ or_options_t *options = get_options_mutable();
+ time_t now = time(NULL);
+ const char *ddir = get_fname("write_fingerprint");
+ char *cp = NULL, *cp2 = NULL;
+ char ed25519_id[BASE64_DIGEST256_LEN + 1];
+
+ (void) arg;
+
+ tt_assert(key);
+
+ options->ORPort_set = 1; /* So that we can get the server ID key */
+ tor_free(options->DataDirectory);
+ options->DataDirectory = tor_strdup(ddir);
+ options->Nickname = tor_strdup("haflinger");
+ set_server_identity_key(key);
+ set_client_identity_key(crypto_pk_dup_key(key));
+
+ load_ed_keys(options, now);
+ tt_assert(get_master_identity_key());
+
+ tt_int_op(0, OP_EQ, check_private_dir(ddir, CPD_CREATE, NULL));
+
+ /* Write fingerprint file */
+ tt_int_op(0, OP_EQ, router_write_fingerprint(0, 1));
+ cp = read_file_to_str(get_fname("write_fingerprint/fingerprint-ed25519"),
+ 0, NULL);
+ digest256_to_base64(ed25519_id,
+ (const char *) get_master_identity_key()->pubkey);
+ tor_asprintf(&cp2, "haflinger %s\n", ed25519_id);
+ tt_str_op(cp, OP_EQ, cp2);
+ tor_free(cp);
+ tor_free(cp2);
+
+ done:
+ crypto_pk_free(key);
+ set_client_identity_key(NULL);
+ tor_free(cp);
+ tor_free(cp2);
+ routerkeys_free_all();
+}
+
+static void
test_routerkeys_ed_certs(void *args)
{
(void)args;
@@ -106,7 +151,7 @@ test_routerkeys_ed_certs(void *args)
for (int i = 0; i <= 1; ++i) {
uint32_t flags = i ? CERT_FLAG_INCLUDE_SIGNING_KEY : 0;
- cert[i] = tor_cert_create(&kp1, 5, &kp2.pubkey, now, 10000, flags);
+ cert[i] = tor_cert_create_ed25519(&kp1, 5, &kp2.pubkey, now, 10000, flags);
tt_assert(cert[i]);
tt_uint_op(cert[i]->sig_bad, OP_EQ, 0);
@@ -399,7 +444,7 @@ test_routerkeys_ed_key_init_split(void *arg)
tt_assert(kp2 != NULL);
tt_assert(cert == NULL);
tt_mem_op(&kp1->pubkey, OP_EQ, &kp2->pubkey, sizeof(kp2->pubkey));
- tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey,
+ tt_assert(fast_mem_is_zero((char*)kp2->seckey.seckey,
sizeof(kp2->seckey.seckey)));
ed25519_keypair_free(kp2); kp2 = NULL;
@@ -409,7 +454,7 @@ test_routerkeys_ed_key_init_split(void *arg)
tt_assert(kp2 != NULL);
tt_assert(cert == NULL);
tt_mem_op(&kp1->pubkey, OP_EQ, &kp2->pubkey, sizeof(kp2->pubkey));
- tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey,
+ tt_assert(fast_mem_is_zero((char*)kp2->seckey.seckey,
sizeof(kp2->seckey.seckey)));
ed25519_keypair_free(kp2); kp2 = NULL;
@@ -455,11 +500,11 @@ test_routerkeys_ed_keys_init_all(void *arg)
options->TestingLinkKeySlop = 2*3600;
#ifdef _WIN32
- mkdir(dir);
- mkdir(keydir);
+ tt_int_op(0, OP_EQ, mkdir(dir));
+ tt_int_op(0, OP_EQ, mkdir(keydir));
#else
- mkdir(dir, 0700);
- mkdir(keydir, 0700);
+ tt_int_op(0, OP_EQ, mkdir(dir, 0700));
+ tt_int_op(0, OP_EQ, mkdir(keydir, 0700));
#endif /* defined(_WIN32) */
options->DataDirectory = dir;
@@ -695,6 +740,7 @@ test_routerkeys_rsa_ed_crosscert(void *arg)
struct testcase_t routerkeys_tests[] = {
TEST(write_fingerprint, TT_FORK),
+ TEST(write_ed25519_identity, TT_FORK),
TEST(ed_certs, TT_FORK),
TEST(ed_key_create, TT_FORK),
TEST(ed_key_init_basic, TT_FORK),
diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c
index 95c9176faa..c7b65006f0 100644
--- a/src/test/test_routerlist.c
+++ b/src/test/test_routerlist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -46,14 +46,12 @@
#include "feature/nodelist/routerstatus_st.h"
#include "lib/encoding/confline.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "test/test.h"
#include "test/test_dir_common.h"
#include "test/log_test_helpers.h"
-void construct_consensus(char **consensus_text_md, time_t now);
-
static authority_cert_t *mock_cert;
static authority_cert_t *
@@ -150,7 +148,7 @@ test_routerlist_launch_descriptor_downloads(void *arg)
smartlist_free(downloadable);
}
-void
+static void
construct_consensus(char **consensus_text_md, time_t now)
{
networkstatus_t *vote = NULL;
@@ -265,7 +263,9 @@ test_router_pick_directory_server_impl(void *arg)
/* Init SR subsystem. */
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
- mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
+ mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1,
+ strlen(AUTHORITY_CERT_1),
+ NULL);
sr_init(0);
UNMOCK(get_my_v3_authority_cert);
@@ -275,7 +275,9 @@ test_router_pick_directory_server_impl(void *arg)
construct_consensus(&consensus_text_md, now);
tt_assert(consensus_text_md);
- con_md = networkstatus_parse_vote_from_string(consensus_text_md, NULL,
+ con_md = networkstatus_parse_vote_from_string(consensus_text_md,
+ strlen(consensus_text_md),
+ NULL,
NS_TYPE_CONSENSUS);
tt_assert(con_md);
tt_int_op(con_md->flavor,OP_EQ, FLAV_MICRODESC);
@@ -301,7 +303,6 @@ test_router_pick_directory_server_impl(void *arg)
tt_assert(!networkstatus_consensus_is_bootstrapping(con_md->valid_until
+ 24*60*60));
/* These times are outside the test validity period */
- tt_assert(networkstatus_consensus_is_bootstrapping(now));
tt_assert(networkstatus_consensus_is_bootstrapping(now + 2*24*60*60));
tt_assert(networkstatus_consensus_is_bootstrapping(now - 2*24*60*60));
@@ -338,18 +339,18 @@ test_router_pick_directory_server_impl(void *arg)
node_router1->rs->is_v2_dir = 0;
node_router3->rs->is_v2_dir = 0;
- tmp_dirport1 = node_router1->rs->dir_port;
- tmp_dirport3 = node_router3->rs->dir_port;
- node_router1->rs->dir_port = 0;
- node_router3->rs->dir_port = 0;
+ tmp_dirport1 = node_router1->rs->ipv4_dirport;
+ tmp_dirport3 = node_router3->rs->ipv4_dirport;
+ node_router1->rs->ipv4_dirport = 0;
+ node_router3->rs->ipv4_dirport = 0;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router2_id, DIGEST_LEN));
rs = NULL;
node_router1->rs->is_v2_dir = 1;
node_router3->rs->is_v2_dir = 1;
- node_router1->rs->dir_port = tmp_dirport1;
- node_router3->rs->dir_port = tmp_dirport3;
+ node_router1->rs->ipv4_dirport = tmp_dirport1;
+ node_router3->rs->ipv4_dirport = tmp_dirport3;
node_router1->is_valid = 0;
node_router3->is_valid = 0;
@@ -378,23 +379,23 @@ test_router_pick_directory_server_impl(void *arg)
options->ReachableORAddresses = policy_line;
policies_parse_from_options(options);
- node_router1->rs->or_port = 444;
- node_router2->rs->or_port = 443;
- node_router3->rs->or_port = 442;
+ node_router1->rs->ipv4_orport = 444;
+ node_router2->rs->ipv4_orport = 443;
+ node_router3->rs->ipv4_orport = 442;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router3_id, DIGEST_LEN));
- node_router1->rs->or_port = 442;
- node_router2->rs->or_port = 443;
- node_router3->rs->or_port = 444;
+ node_router1->rs->ipv4_orport = 442;
+ node_router2->rs->ipv4_orport = 443;
+ node_router3->rs->ipv4_orport = 444;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN));
/* Fascist firewall and overloaded */
- node_router1->rs->or_port = 442;
- node_router2->rs->or_port = 443;
- node_router3->rs->or_port = 442;
+ node_router1->rs->ipv4_orport = 442;
+ node_router2->rs->ipv4_orport = 443;
+ node_router3->rs->ipv4_orport = 442;
node_router3->rs->last_dir_503_at = now;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
tt_ptr_op(rs, OP_NE, NULL);
@@ -407,12 +408,12 @@ test_router_pick_directory_server_impl(void *arg)
policy_line->value = tor_strdup("accept *:80, reject *:*");
options->ReachableDirAddresses = policy_line;
policies_parse_from_options(options);
- node_router1->rs->or_port = 442;
- node_router2->rs->or_port = 441;
- node_router3->rs->or_port = 443;
- node_router1->rs->dir_port = 80;
- node_router2->rs->dir_port = 80;
- node_router3->rs->dir_port = 81;
+ node_router1->rs->ipv4_orport = 442;
+ node_router2->rs->ipv4_orport = 441;
+ node_router3->rs->ipv4_orport = 443;
+ node_router1->rs->ipv4_dirport = 80;
+ node_router2->rs->ipv4_dirport = 80;
+ node_router3->rs->ipv4_dirport = 81;
node_router1->rs->last_dir_503_at = now;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
tt_ptr_op(rs, OP_NE, NULL);
@@ -475,7 +476,9 @@ test_directory_guard_fetch_with_no_dirinfo(void *arg)
/* Initialize the SRV subsystem */
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
- mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
+ mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1,
+ strlen(AUTHORITY_CERT_1),
+ NULL);
sr_init(0);
UNMOCK(get_my_v3_authority_cert);
@@ -626,7 +629,7 @@ mock_clock_skew_warning(const connection_t *conn, long apparent_skew,
(void)conn;
mock_apparent_skew = apparent_skew;
tt_int_op(trusted, OP_EQ, 1);
- tt_int_op(domain, OP_EQ, LD_GENERAL);
+ tt_i64_op(domain, OP_EQ, LD_GENERAL);
tt_str_op(received, OP_EQ, "microdesc flavor consensus");
tt_str_op(source, OP_EQ, "CONSENSUS");
done:
@@ -648,7 +651,9 @@ test_skew_common(void *arg, time_t now, unsigned long *offset)
/* Initialize the SRV subsystem */
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
- mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
+ mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1,
+ strlen(AUTHORITY_CERT_1),
+ NULL);
sr_init(0);
UNMOCK(get_my_v3_authority_cert);
@@ -662,7 +667,8 @@ test_skew_common(void *arg, time_t now, unsigned long *offset)
MOCK(clock_skew_warning, mock_clock_skew_warning);
/* Caller will call teardown_capture_of_logs() */
setup_capture_of_logs(LOG_WARN);
- retval = networkstatus_set_current_consensus(consensus, "microdesc", 0,
+ retval = networkstatus_set_current_consensus(consensus, strlen(consensus),
+ "microdesc", 0,
NULL);
done:
diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c
index c45f0e1595..d00eefa23f 100644
--- a/src/test/test_routerset.c
+++ b/src/test/test_routerset.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERSET_PRIVATE
@@ -18,17 +18,13 @@
#include "test/test.h"
-#define NS_MODULE routerset
-
-#define NS_SUBMODULE routerset_new
-
/*
* Functional (blackbox) test to determine that each member of the routerset
* is non-NULL
*/
static void
-NS(test_main)(void *arg)
+test_rset_new(void *arg)
{
routerset_t *rs;
(void)arg;
@@ -46,15 +42,12 @@ NS(test_main)(void *arg)
routerset_free(rs);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_get_countryname
-
/*
* Functional test to strip the braces from a "{xx}" country code string.
*/
static void
-NS(test_main)(void *arg)
+test_rset_get_countryname(void *arg)
{
const char *input;
char *name;
@@ -91,257 +84,272 @@ NS(test_main)(void *arg)
tor_free(name);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_refresh_counties, geoip_not_loaded)
-
/*
* Structural (whitebox) test for routerset_refresh_counties, when the GeoIP DB
* is not loaded.
*/
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
-NS_DECL(int, geoip_get_n_countries, (void));
+static int rset_refresh_geoip_not_loaded_geoip_is_loaded(sa_family_t family);
+static int rset_refresh_geoip_not_loaded_geoip_is_loaded_called = 0;
+static int rset_refresh_geoip_not_loaded_geoip_get_n_countries(void);
+static int rset_refresh_geoip_not_loaded_geoip_get_n_countries_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_refresh_geoip_not_loaded(void *arg)
{
routerset_t *set = routerset_new();
(void)arg;
- NS_MOCK(geoip_is_loaded);
- NS_MOCK(geoip_get_n_countries);
+ MOCK(geoip_is_loaded,
+ rset_refresh_geoip_not_loaded_geoip_is_loaded);
+ MOCK(geoip_get_n_countries,
+ rset_refresh_geoip_not_loaded_geoip_get_n_countries);
routerset_refresh_countries(set);
tt_ptr_op(set->countries, OP_EQ, NULL);
tt_int_op(set->n_countries, OP_EQ, 0);
- tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 0);
+ tt_int_op(rset_refresh_geoip_not_loaded_geoip_is_loaded_called, OP_EQ, 1);
+ tt_int_op(rset_refresh_geoip_not_loaded_geoip_get_n_countries_called,
+ OP_EQ, 0);
done:
- NS_UNMOCK(geoip_is_loaded);
- NS_UNMOCK(geoip_get_n_countries);
+ UNMOCK(geoip_is_loaded);
+ UNMOCK(geoip_get_n_countries);
routerset_free(set);
}
static int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_refresh_geoip_not_loaded_geoip_is_loaded(sa_family_t family)
{
(void)family;
- CALLED(geoip_is_loaded)++;
+ rset_refresh_geoip_not_loaded_geoip_is_loaded_called++;
return 0;
}
static int
-NS(geoip_get_n_countries)(void)
+rset_refresh_geoip_not_loaded_geoip_get_n_countries(void)
{
- CALLED(geoip_get_n_countries)++;
+ rset_refresh_geoip_not_loaded_geoip_get_n_countries_called++;
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_refresh_counties, no_countries)
-
/*
* Structural test for routerset_refresh_counties, when there are no countries.
*/
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
-NS_DECL(int, geoip_get_n_countries, (void));
-NS_DECL(country_t, geoip_get_country, (const char *country));
+static int rset_refresh_no_countries_geoip_is_loaded(sa_family_t family);
+static int rset_refresh_no_countries_geoip_is_loaded_called = 0;
+static int rset_refresh_no_countries_geoip_get_n_countries(void);
+static int rset_refresh_no_countries_geoip_get_n_countries_called = 0;
+static country_t rset_refresh_no_countries_geoip_get_country(
+ const char *country);
+static int rset_refresh_no_countries_geoip_get_country_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_refresh_no_countries(void *arg)
{
routerset_t *set = routerset_new();
(void)arg;
- NS_MOCK(geoip_is_loaded);
- NS_MOCK(geoip_get_n_countries);
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_is_loaded,
+ rset_refresh_no_countries_geoip_is_loaded);
+ MOCK(geoip_get_n_countries,
+ rset_refresh_no_countries_geoip_get_n_countries);
+ MOCK(geoip_get_country,
+ rset_refresh_no_countries_geoip_get_country);
routerset_refresh_countries(set);
tt_ptr_op(set->countries, OP_NE, NULL);
tt_int_op(set->n_countries, OP_EQ, 1);
tt_int_op((unsigned int)(*set->countries), OP_EQ, 0);
- tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_country), OP_EQ, 0);
+ tt_int_op(rset_refresh_no_countries_geoip_is_loaded_called, OP_EQ, 1);
+ tt_int_op(rset_refresh_no_countries_geoip_get_n_countries_called, OP_EQ, 1);
+ tt_int_op(rset_refresh_no_countries_geoip_get_country_called, OP_EQ, 0);
done:
- NS_UNMOCK(geoip_is_loaded);
- NS_UNMOCK(geoip_get_n_countries);
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_is_loaded);
+ UNMOCK(geoip_get_n_countries);
+ UNMOCK(geoip_get_country);
routerset_free(set);
}
static int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_refresh_no_countries_geoip_is_loaded(sa_family_t family)
{
(void)family;
- CALLED(geoip_is_loaded)++;
+ rset_refresh_no_countries_geoip_is_loaded_called++;
return 1;
}
static int
-NS(geoip_get_n_countries)(void)
+rset_refresh_no_countries_geoip_get_n_countries(void)
{
- CALLED(geoip_get_n_countries)++;
+ rset_refresh_no_countries_geoip_get_n_countries_called++;
return 1;
}
static country_t
-NS(geoip_get_country)(const char *countrycode)
+rset_refresh_no_countries_geoip_get_country(const char *countrycode)
{
(void)countrycode;
- CALLED(geoip_get_country)++;
+ rset_refresh_no_countries_geoip_get_country_called++;
return 1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_refresh_counties, one_valid_country)
-
/*
* Structural test for routerset_refresh_counties, with one valid country.
*/
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
-NS_DECL(int, geoip_get_n_countries, (void));
-NS_DECL(country_t, geoip_get_country, (const char *country));
+static int rset_refresh_one_valid_country_geoip_is_loaded(sa_family_t family);
+static int rset_refresh_one_valid_country_geoip_is_loaded_called = 0;
+static int rset_refresh_one_valid_country_geoip_get_n_countries(void);
+static int rset_refresh_one_valid_country_geoip_get_n_countries_called = 0;
+static country_t rset_refresh_one_valid_country_geoip_get_country(
+ const char *country);
+static int rset_refresh_one_valid_country_geoip_get_country_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_refresh_one_valid_country(void *arg)
{
routerset_t *set = routerset_new();
(void)arg;
- NS_MOCK(geoip_is_loaded);
- NS_MOCK(geoip_get_n_countries);
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_is_loaded,
+ rset_refresh_one_valid_country_geoip_is_loaded);
+ MOCK(geoip_get_n_countries,
+ rset_refresh_one_valid_country_geoip_get_n_countries);
+ MOCK(geoip_get_country,
+ rset_refresh_one_valid_country_geoip_get_country);
smartlist_add(set->country_names, tor_strndup("foo", 3));
routerset_refresh_countries(set);
tt_ptr_op(set->countries, OP_NE, NULL);
tt_int_op(set->n_countries, OP_EQ, 2);
- tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_country), OP_EQ, 1);
+ tt_int_op(rset_refresh_one_valid_country_geoip_is_loaded_called, OP_EQ, 1);
+ tt_int_op(rset_refresh_one_valid_country_geoip_get_n_countries_called,
+ OP_EQ, 1);
+ tt_int_op(rset_refresh_one_valid_country_geoip_get_country_called, OP_EQ, 1);
tt_int_op((unsigned int)(*set->countries), OP_NE, 0);
done:
- NS_UNMOCK(geoip_is_loaded);
- NS_UNMOCK(geoip_get_n_countries);
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_is_loaded);
+ UNMOCK(geoip_get_n_countries);
+ UNMOCK(geoip_get_country);
routerset_free(set);
}
static int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_refresh_one_valid_country_geoip_is_loaded(sa_family_t family)
{
(void)family;
- CALLED(geoip_is_loaded)++;
+ rset_refresh_one_valid_country_geoip_is_loaded_called++;
return 1;
}
static int
-NS(geoip_get_n_countries)(void)
+rset_refresh_one_valid_country_geoip_get_n_countries(void)
{
- CALLED(geoip_get_n_countries)++;
+ rset_refresh_one_valid_country_geoip_get_n_countries_called++;
return 2;
}
static country_t
-NS(geoip_get_country)(const char *countrycode)
+rset_refresh_one_valid_country_geoip_get_country(const char *countrycode)
{
(void)countrycode;
- CALLED(geoip_get_country)++;
+ rset_refresh_one_valid_country_geoip_get_country_called++;
return 1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_refresh_counties, one_invalid_country)
-
/*
* Structural test for routerset_refresh_counties, with one invalid
* country code..
*/
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
-NS_DECL(int, geoip_get_n_countries, (void));
-NS_DECL(country_t, geoip_get_country, (const char *country));
+static int rset_refresh_one_invalid_country_geoip_is_loaded(
+ sa_family_t family);
+static int rset_refresh_one_invalid_country_geoip_is_loaded_called = 0;
+static int rset_refresh_one_invalid_country_geoip_get_n_countries(void);
+static int rset_refresh_one_invalid_country_geoip_get_n_countries_called = 0;
+static country_t rset_refresh_one_invalid_country_geoip_get_country(
+ const char *country);
+static int rset_refresh_one_invalid_country_geoip_get_country_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_refresh_one_invalid_country(void *arg)
{
routerset_t *set = routerset_new();
(void)arg;
- NS_MOCK(geoip_is_loaded);
- NS_MOCK(geoip_get_n_countries);
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_is_loaded,
+ rset_refresh_one_invalid_country_geoip_is_loaded);
+ MOCK(geoip_get_n_countries,
+ rset_refresh_one_invalid_country_geoip_get_n_countries);
+ MOCK(geoip_get_country,
+ rset_refresh_one_invalid_country_geoip_get_country);
smartlist_add(set->country_names, tor_strndup("foo", 3));
routerset_refresh_countries(set);
tt_ptr_op(set->countries, OP_NE, NULL);
tt_int_op(set->n_countries, OP_EQ, 2);
- tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_country), OP_EQ, 1);
+ tt_int_op(rset_refresh_one_invalid_country_geoip_is_loaded_called, OP_EQ, 1);
+ tt_int_op(rset_refresh_one_invalid_country_geoip_get_n_countries_called,
+ OP_EQ, 1);
+ tt_int_op(rset_refresh_one_invalid_country_geoip_get_country_called,
+ OP_EQ, 1);
tt_int_op((unsigned int)(*set->countries), OP_EQ, 0);
done:
- NS_UNMOCK(geoip_is_loaded);
- NS_UNMOCK(geoip_get_n_countries);
- NS_UNMOCK(geoip_get_country);
+ UNMOCK(geoip_is_loaded);
+ UNMOCK(geoip_get_n_countries);
+ UNMOCK(geoip_get_country);
routerset_free(set);
}
static int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_refresh_one_invalid_country_geoip_is_loaded(sa_family_t family)
{
(void)family;
- CALLED(geoip_is_loaded)++;
+ rset_refresh_one_invalid_country_geoip_is_loaded_called++;
return 1;
}
static int
-NS(geoip_get_n_countries)(void)
+rset_refresh_one_invalid_country_geoip_get_n_countries(void)
{
- CALLED(geoip_get_n_countries)++;
+ rset_refresh_one_invalid_country_geoip_get_n_countries_called++;
return 2;
}
static country_t
-NS(geoip_get_country)(const char *countrycode)
+rset_refresh_one_invalid_country_geoip_get_country(const char *countrycode)
{
(void)countrycode;
- CALLED(geoip_get_country)++;
+ rset_refresh_one_invalid_country_geoip_get_country_called++;
return -1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, malformed)
-
/*
* Functional test, with a malformed string to parse.
*/
static void
-NS(test_main)(void *arg)
+test_rset_parse_malformed(void *arg)
{
routerset_t *set = routerset_new();
const char *s = "_";
@@ -356,16 +364,13 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, valid_hexdigest)
-
/*
* Functional test for routerset_parse, that routerset_parse returns 0
* on a valid hexdigest entry.
*/
static void
-NS(test_main)(void *arg)
+test_rset_parse_valid_hexdigest(void *arg)
{
routerset_t *set;
const char *s;
@@ -382,15 +387,12 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, valid_nickname)
-
/*
* Functional test for routerset_parse, when given a valid nickname as input.
*/
static void
-NS(test_main)(void *arg)
+test_rset_parse_valid_nickname(void *arg)
{
routerset_t *set;
const char *s;
@@ -407,15 +409,12 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, get_countryname)
-
/*
* Functional test for routerset_parse, when given a valid countryname.
*/
static void
-NS(test_main)(void *arg)
+test_rset_parse_get_countryname(void *arg)
{
routerset_t *set;
const char *s;
@@ -432,158 +431,158 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, policy_wildcard)
-
/*
* Structural test for routerset_parse, when given a valid wildcard policy.
*/
-NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
- (const char *s, int assume_action, int *malformed_list));
+static addr_policy_t * rset_parse_policy_wildcard_parse_item_from_string(
+ const char *s, int assume_action, int *malformed_list);
+static int rset_parse_policy_wildcard_parse_item_from_string_called = 0;
-static addr_policy_t *NS(mock_addr_policy);
+static addr_policy_t *rset_parse_policy_wildcard_mock_addr_policy;
static void
-NS(test_main)(void *arg)
+test_rset_parse_policy_wildcard(void *arg)
{
routerset_t *set;
const char *s;
int r;
(void)arg;
- NS_MOCK(router_parse_addr_policy_item_from_string);
- NS(mock_addr_policy) = tor_malloc_zero(sizeof(addr_policy_t));
+ MOCK(router_parse_addr_policy_item_from_string,
+ rset_parse_policy_wildcard_parse_item_from_string);
+ rset_parse_policy_wildcard_mock_addr_policy =
+ tor_malloc_zero(sizeof(addr_policy_t));
set = routerset_new();
s = "*";
r = routerset_parse(set, s, "");
tt_int_op(r, OP_EQ, 0);
tt_int_op(smartlist_len(set->policies), OP_NE, 0);
- tt_int_op(CALLED(router_parse_addr_policy_item_from_string), OP_EQ, 1);
+ tt_int_op(rset_parse_policy_wildcard_parse_item_from_string_called,
+ OP_EQ, 1);
done:
routerset_free(set);
}
addr_policy_t *
-NS(router_parse_addr_policy_item_from_string)(const char *s,
+rset_parse_policy_wildcard_parse_item_from_string(const char *s,
int assume_action,
int *malformed_list)
{
(void)s;
(void)assume_action;
(void)malformed_list;
- CALLED(router_parse_addr_policy_item_from_string)++;
+ rset_parse_policy_wildcard_parse_item_from_string_called++;
- return NS(mock_addr_policy);
+ return rset_parse_policy_wildcard_mock_addr_policy;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, policy_ipv4)
-
/*
* Structural test for routerset_parse, when given a valid IPv4 address
* literal policy.
*/
-NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
- (const char *s, int assume_action, int *bogus));
+static addr_policy_t * rset_parse_policy_ipv4_parse_item_from_string(
+ const char *s, int assume_action, int *bogus);
+static int rset_parse_policy_ipv4_parse_item_from_string_called = 0;
-static addr_policy_t *NS(mock_addr_policy);
+static addr_policy_t *rset_parse_policy_ipv4_mock_addr_policy;
static void
-NS(test_main)(void *arg)
+test_rset_parse_policy_ipv4(void *arg)
{
routerset_t *set;
const char *s;
int r;
(void)arg;
- NS_MOCK(router_parse_addr_policy_item_from_string);
- NS(mock_addr_policy) = tor_malloc_zero(sizeof(addr_policy_t));
+ MOCK(router_parse_addr_policy_item_from_string,
+ rset_parse_policy_ipv4_parse_item_from_string);
+ rset_parse_policy_ipv4_mock_addr_policy =
+ tor_malloc_zero(sizeof(addr_policy_t));
set = routerset_new();
s = "127.0.0.1";
r = routerset_parse(set, s, "");
tt_int_op(r, OP_EQ, 0);
tt_int_op(smartlist_len(set->policies), OP_NE, 0);
- tt_int_op(CALLED(router_parse_addr_policy_item_from_string), OP_EQ, 1);
+ tt_int_op(rset_parse_policy_ipv4_parse_item_from_string_called, OP_EQ, 1);
done:
routerset_free(set);
}
addr_policy_t *
-NS(router_parse_addr_policy_item_from_string)(const char *s, int assume_action,
- int *bogus)
+rset_parse_policy_ipv4_parse_item_from_string(
+ const char *s, int assume_action,
+ int *bogus)
{
(void)s;
(void)assume_action;
- CALLED(router_parse_addr_policy_item_from_string)++;
+ rset_parse_policy_ipv4_parse_item_from_string_called++;
*bogus = 0;
- return NS(mock_addr_policy);
+ return rset_parse_policy_ipv4_mock_addr_policy;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_parse, policy_ipv6)
-
/*
* Structural test for routerset_parse, when given a valid IPv6 address
* literal policy.
*/
-NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
- (const char *s, int assume_action, int *bad));
+static addr_policy_t * rset_parse_policy_ipv6_parse_item_from_string(
+ const char *s, int assume_action, int *bad);
+static int rset_parse_policy_ipv6_parse_item_from_string_called = 0;
-static addr_policy_t *NS(mock_addr_policy);
+static addr_policy_t *rset_parse_policy_ipv6_mock_addr_policy;
static void
-NS(test_main)(void *arg)
+test_rset_parse_policy_ipv6(void *arg)
{
routerset_t *set;
const char *s;
int r;
(void)arg;
- NS_MOCK(router_parse_addr_policy_item_from_string);
- NS(mock_addr_policy) = tor_malloc_zero(sizeof(addr_policy_t));
+ MOCK(router_parse_addr_policy_item_from_string,
+ rset_parse_policy_ipv6_parse_item_from_string);
+ rset_parse_policy_ipv6_mock_addr_policy =
+ tor_malloc_zero(sizeof(addr_policy_t));
set = routerset_new();
s = "::1";
r = routerset_parse(set, s, "");
tt_int_op(r, OP_EQ, 0);
tt_int_op(smartlist_len(set->policies), OP_NE, 0);
- tt_int_op(CALLED(router_parse_addr_policy_item_from_string), OP_EQ, 1);
+ tt_int_op(rset_parse_policy_ipv6_parse_item_from_string_called, OP_EQ, 1);
done:
routerset_free(set);
}
addr_policy_t *
-NS(router_parse_addr_policy_item_from_string)(const char *s,
+rset_parse_policy_ipv6_parse_item_from_string(const char *s,
int assume_action, int *bad)
{
(void)s;
(void)assume_action;
- CALLED(router_parse_addr_policy_item_from_string)++;
+ rset_parse_policy_ipv6_parse_item_from_string_called++;
*bad = 0;
- return NS(mock_addr_policy);
+ return rset_parse_policy_ipv6_mock_addr_policy;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_union, source_bad)
-
/*
* Structural test for routerset_union, when given a bad source argument.
*/
-NS_DECL(smartlist_t *, smartlist_new, (void));
+static smartlist_t * rset_union_source_bad_smartlist_new(void);
+static int rset_union_source_bad_smartlist_new_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_union_source_bad(void *arg)
{
routerset_t *set, *bad_set;
(void)arg;
@@ -593,16 +592,17 @@ NS(test_main)(void *arg)
smartlist_free(bad_set->list);
bad_set->list = NULL;
- NS_MOCK(smartlist_new);
+ MOCK(smartlist_new,
+ rset_union_source_bad_smartlist_new);
routerset_union(set, NULL);
- tt_int_op(CALLED(smartlist_new), OP_EQ, 0);
+ tt_int_op(rset_union_source_bad_smartlist_new_called, OP_EQ, 0);
routerset_union(set, bad_set);
- tt_int_op(CALLED(smartlist_new), OP_EQ, 0);
+ tt_int_op(rset_union_source_bad_smartlist_new_called, OP_EQ, 0);
done:
- NS_UNMOCK(smartlist_new);
+ UNMOCK(smartlist_new);
routerset_free(set);
/* Just recreate list, so we can simply use routerset_free. */
@@ -611,22 +611,19 @@ NS(test_main)(void *arg)
}
static smartlist_t *
-NS(smartlist_new)(void)
+rset_union_source_bad_smartlist_new(void)
{
- CALLED(smartlist_new)++;
+ rset_union_source_bad_smartlist_new_called++;
return NULL;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_union, one)
-
/*
* Functional test for routerset_union.
*/
static void
-NS(test_main)(void *arg)
+test_rset_union_one(void *arg)
{
routerset_t *src = routerset_new();
routerset_t *tgt;
@@ -643,15 +640,12 @@ NS(test_main)(void *arg)
routerset_free(tgt);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_is_list
-
/*
* Functional tests for routerset_is_list.
*/
static void
-NS(test_main)(void *arg)
+test_rset_is_list(void *arg)
{
routerset_t *set;
addr_policy_t *policy;
@@ -696,15 +690,12 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_needs_geoip
-
/*
* Functional tests for routerset_needs_geoip.
*/
static void
-NS(test_main)(void *arg)
+test_rset_needs_geoip(void *arg)
{
routerset_t *set;
int needs_geoip;
@@ -731,15 +722,12 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_is_empty
-
/*
* Functional tests for routerset_is_empty.
*/
static void
-NS(test_main)(void *arg)
+test_rset_is_empty(void *arg)
{
routerset_t *set = NULL;
int is_empty;
@@ -765,16 +753,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, null_set_or_null_set_list)
-
/*
* Functional test for routerset_contains, when given a NULL set or the
* set has a NULL list.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_null_set_or_list(void *arg)
{
routerset_t *set = NULL;
int contains;
@@ -794,16 +779,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_nickname)
-
/*
* Functional test for routerset_contains, when given a valid routerset but a
* NULL nickname.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_null_nickname(void *arg)
{
routerset_t *set = routerset_new();
char *nickname = NULL;
@@ -819,16 +801,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_nickname)
-
/*
* Functional test for routerset_contains, when given a valid routerset
* and the nickname is in the routerset.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_nickname(void *arg)
{
routerset_t *set = routerset_new();
const char *nickname;
@@ -845,16 +824,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_nickname)
-
/*
* Functional test for routerset_contains, when given a valid routerset
* and the nickname is not in the routerset.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_no_nickname(void *arg)
{
routerset_t *set = routerset_new();
int contains;
@@ -869,16 +845,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_digest)
-
/*
* Functional test for routerset_contains, when given a valid routerset
* and the digest is contained in the routerset.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_digest(void *arg)
{
routerset_t *set = routerset_new();
int contains;
@@ -894,16 +867,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_digest)
-
/*
* Functional test for routerset_contains, when given a valid routerset
* and the digest is not contained in the routerset.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_no_digest(void *arg)
{
routerset_t *set = routerset_new();
int contains;
@@ -920,16 +890,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_digest)
-
/*
* Functional test for routerset_contains, when given a valid routerset
* and the digest is NULL.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_null_digest(void *arg)
{
routerset_t *set = routerset_new();
int contains;
@@ -945,34 +912,34 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_addr)
-
/*
* Structural test for routerset_contains, when given a valid routerset
* and the address is rejected by policy.
*/
-NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
- (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+static addr_policy_result_t rset_contains_addr_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy);
+static int rset_contains_addr_cmp_addr_to_policy_called = 0;
static tor_addr_t MOCK_TOR_ADDR;
#define MOCK_TOR_ADDR_PTR (&MOCK_TOR_ADDR)
static void
-NS(test_main)(void *arg)
+test_rset_contains_addr(void *arg)
{
routerset_t *set = routerset_new();
tor_addr_t *addr = MOCK_TOR_ADDR_PTR;
int contains;
(void)arg;
- NS_MOCK(compare_tor_addr_to_addr_policy);
+ MOCK(compare_tor_addr_to_addr_policy,
+ rset_contains_addr_cmp_addr_to_policy);
contains = routerset_contains(set, addr, 0, NULL, NULL, 0);
routerset_free(set);
- tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
+ tt_int_op(rset_contains_addr_cmp_addr_to_policy_called, OP_EQ, 1);
tt_int_op(contains, OP_EQ, 3);
done:
@@ -980,12 +947,12 @@ NS(test_main)(void *arg)
}
addr_policy_result_t
-NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+rset_contains_addr_cmp_addr_to_policy(const tor_addr_t *addr, uint16_t port,
const smartlist_t *policy)
{
(void)port;
(void)policy;
- CALLED(compare_tor_addr_to_addr_policy)++;
+ rset_contains_addr_cmp_addr_to_policy_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
return ADDR_POLICY_REJECTED;
@@ -993,31 +960,31 @@ NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_addr)
-
/*
* Structural test for routerset_contains, when given a valid routerset
* and the address is not rejected by policy.
*/
-NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
- (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+static addr_policy_result_t rset_contains_no_addr_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy);
+static int rset_contains_no_addr_cmp_addr_to_policy_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_contains_no_addr(void *arg)
{
routerset_t *set = routerset_new();
tor_addr_t *addr = MOCK_TOR_ADDR_PTR;
int contains;
(void)arg;
- NS_MOCK(compare_tor_addr_to_addr_policy);
+ MOCK(compare_tor_addr_to_addr_policy,
+ rset_contains_no_addr_cmp_addr_to_policy);
contains = routerset_contains(set, addr, 0, NULL, NULL, 0);
routerset_free(set);
- tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
+ tt_int_op(rset_contains_no_addr_cmp_addr_to_policy_called, OP_EQ, 1);
tt_int_op(contains, OP_EQ, 0);
done:
@@ -1025,12 +992,12 @@ NS(test_main)(void *arg)
}
addr_policy_result_t
-NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+rset_contains_no_addr_cmp_addr_to_policy(const tor_addr_t *addr, uint16_t port,
const smartlist_t *policy)
{
(void)port;
(void)policy;
- CALLED(compare_tor_addr_to_addr_policy)++;
+ rset_contains_no_addr_cmp_addr_to_policy_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
return ADDR_POLICY_ACCEPTED;
@@ -1039,25 +1006,25 @@ NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_addr)
-
/*
* Structural test for routerset_contains, when given a valid routerset
* and the address is NULL.
*/
-NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
- (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+static addr_policy_result_t rset_contains_null_addr_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy);
+static int rset_contains_null_addr_cmp_addr_to_policy_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_contains_null_addr(void *arg)
{
routerset_t *set = routerset_new();
int contains;
(void)arg;
- NS_MOCK(compare_tor_addr_to_addr_policy);
+ MOCK(compare_tor_addr_to_addr_policy,
+ rset_contains_null_addr_cmp_addr_to_policy);
contains = routerset_contains(set, NULL, 0, NULL, NULL, 0);
routerset_free(set);
@@ -1069,12 +1036,13 @@ NS(test_main)(void *arg)
}
addr_policy_result_t
-NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+rset_contains_null_addr_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
const smartlist_t *policy)
{
(void)port;
(void)policy;
- CALLED(compare_tor_addr_to_addr_policy)++;
+ rset_contains_null_addr_cmp_addr_to_policy_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
return ADDR_POLICY_ACCEPTED;
@@ -1083,27 +1051,30 @@ NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, countries_no_geoip)
-
/*
* Structural test for routerset_contains, when there is no matching country
* for the address.
*/
-NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
- (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
-NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+static addr_policy_result_t rset_countries_no_geoip_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy);
+static int rset_countries_no_geoip_cmp_addr_to_policy_called = 0;
+static int rset_countries_no_geoip_geoip_get_country_by_addr(
+ const tor_addr_t *addr);
+static int rset_countries_no_geoip_geoip_get_country_by_addr_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_countries_no_geoip(void *arg)
{
routerset_t *set = routerset_new();
int contains = 1;
(void)arg;
- NS_MOCK(compare_tor_addr_to_addr_policy);
- NS_MOCK(geoip_get_country_by_addr);
+ MOCK(compare_tor_addr_to_addr_policy,
+ rset_countries_no_geoip_cmp_addr_to_policy);
+ MOCK(geoip_get_country_by_addr,
+ rset_countries_no_geoip_geoip_get_country_by_addr);
set->countries = bitarray_init_zero(1);
bitarray_set(set->countries, 1);
@@ -1111,20 +1082,23 @@ NS(test_main)(void *arg)
routerset_free(set);
tt_int_op(contains, OP_EQ, 0);
- tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_country_by_addr), OP_EQ, 1);
+ tt_int_op(rset_countries_no_geoip_cmp_addr_to_policy_called,
+ OP_EQ, 1);
+ tt_int_op(rset_countries_no_geoip_geoip_get_country_by_addr_called,
+ OP_EQ, 1);
done:
;
}
addr_policy_result_t
-NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+rset_countries_no_geoip_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
const smartlist_t *policy)
{
(void)port;
(void)policy;
- CALLED(compare_tor_addr_to_addr_policy)++;
+ rset_countries_no_geoip_cmp_addr_to_policy_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
done:
@@ -1132,36 +1106,39 @@ NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
}
int
-NS(geoip_get_country_by_addr)(const tor_addr_t *addr)
+rset_countries_no_geoip_geoip_get_country_by_addr(const tor_addr_t *addr)
{
- CALLED(geoip_get_country_by_addr)++;
+ rset_countries_no_geoip_geoip_get_country_by_addr_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
done:
return -1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains, countries_geoip)
-
/*
* Structural test for routerset_contains, when there a matching country
* for the address.
*/
-NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
- (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
-NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+static addr_policy_result_t rset_countries_geoip_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy);
+static int rset_countries_geoip_cmp_addr_to_policy_called = 0;
+static int rset_countries_geoip_geoip_get_country_by_addr(
+ const tor_addr_t *addr);
+static int rset_countries_geoip_geoip_get_country_by_addr_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_countries_geoip(void *arg)
{
routerset_t *set = routerset_new();
int contains = 1;
(void)arg;
- NS_MOCK(compare_tor_addr_to_addr_policy);
- NS_MOCK(geoip_get_country_by_addr);
+ MOCK(compare_tor_addr_to_addr_policy,
+ rset_countries_geoip_cmp_addr_to_policy);
+ MOCK(geoip_get_country_by_addr,
+ rset_countries_geoip_geoip_get_country_by_addr);
set->n_countries = 2;
set->countries = bitarray_init_zero(1);
@@ -1170,20 +1147,24 @@ NS(test_main)(void *arg)
routerset_free(set);
tt_int_op(contains, OP_EQ, 2);
- tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
- tt_int_op(CALLED(geoip_get_country_by_addr), OP_EQ, 1);
+ tt_int_op(
+ rset_countries_geoip_cmp_addr_to_policy_called,
+ OP_EQ, 1);
+ tt_int_op(rset_countries_geoip_geoip_get_country_by_addr_called,
+ OP_EQ, 1);
done:
;
}
addr_policy_result_t
-NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+rset_countries_geoip_cmp_addr_to_policy(
+ const tor_addr_t *addr, uint16_t port,
const smartlist_t *policy)
{
(void)port;
(void)policy;
- CALLED(compare_tor_addr_to_addr_policy)++;
+ rset_countries_geoip_cmp_addr_to_policy_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
done:
@@ -1191,25 +1172,22 @@ NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
}
int
-NS(geoip_get_country_by_addr)(const tor_addr_t *addr)
+rset_countries_geoip_geoip_get_country_by_addr(const tor_addr_t *addr)
{
- CALLED(geoip_get_country_by_addr)++;
+ rset_countries_geoip_geoip_get_country_by_addr_called++;
tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
done:
return 1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, only_flag_and_no_ccs)
-
/*
* Functional test for routerset_add_unknown_ccs, where only_if_some_cc_set
* is set and there are no country names.
*/
static void
-NS(test_main)(void *arg)
+test_rset_add_unknown_ccs_only_flag(void *arg)
{
routerset_t *set = routerset_new();
routerset_t **setp = &set;
@@ -1224,26 +1202,26 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, creates_set)
-
/*
* Functional test for routerset_add_unknown_ccs, where the set argument
* is created if passed in as NULL.
*/
/* The mock is only used to stop the test from asserting erroneously. */
-NS_DECL(country_t, geoip_get_country, (const char *country));
+static country_t rset_add_unknown_ccs_creates_set_geoip_get_country(
+ const char *country);
+static int rset_add_unknown_ccs_creates_set_geoip_get_country_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_add_unknown_ccs_creates_set(void *arg)
{
routerset_t *set = NULL;
routerset_t **setp = &set;
int r;
(void)arg;
- NS_MOCK(geoip_get_country);
+ MOCK(geoip_get_country,
+ rset_add_unknown_ccs_creates_set_geoip_get_country);
r = routerset_add_unknown_ccs(setp, 0);
@@ -1256,35 +1234,38 @@ NS(test_main)(void *arg)
}
country_t
-NS(geoip_get_country)(const char *country)
+rset_add_unknown_ccs_creates_set_geoip_get_country(const char *country)
{
(void)country;
- CALLED(geoip_get_country)++;
+ rset_add_unknown_ccs_creates_set_geoip_get_country_called++;
return -1;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, add_unknown)
-
/*
* Structural test for routerset_add_unknown_ccs, that the "{??}"
* country code is added to the list.
*/
-NS_DECL(country_t, geoip_get_country, (const char *country));
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+static country_t rset_add_unknown_ccs_add_unknown_geoip_get_country(
+ const char *country);
+static int rset_add_unknown_ccs_add_unknown_geoip_get_country_called = 0;
+static int rset_add_unknown_ccs_add_unknown_geoip_is_loaded(
+ sa_family_t family);
+static int rset_add_unknown_ccs_add_unknown_geoip_is_loaded_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_add_unknown_ccs_add_unknown(void *arg)
{
routerset_t *set = routerset_new();
routerset_t **setp = &set;
int r;
(void)arg;
- NS_MOCK(geoip_get_country);
- NS_MOCK(geoip_is_loaded);
+ MOCK(geoip_get_country,
+ rset_add_unknown_ccs_add_unknown_geoip_get_country);
+ MOCK(geoip_is_loaded,
+ rset_add_unknown_ccs_add_unknown_geoip_is_loaded);
r = routerset_add_unknown_ccs(setp, 0);
@@ -1298,11 +1279,11 @@ NS(test_main)(void *arg)
}
country_t
-NS(geoip_get_country)(const char *country)
+rset_add_unknown_ccs_add_unknown_geoip_get_country(const char *country)
{
int arg_is_qq, arg_is_a1;
- CALLED(geoip_get_country)++;
+ rset_add_unknown_ccs_add_unknown_geoip_get_country_called++;
arg_is_qq = !strcmp(country, "??");
arg_is_a1 = !strcmp(country, "A1");
@@ -1317,9 +1298,9 @@ NS(geoip_get_country)(const char *country)
}
int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_add_unknown_ccs_add_unknown_geoip_is_loaded(sa_family_t family)
{
- CALLED(geoip_is_loaded)++;
+ rset_add_unknown_ccs_add_unknown_geoip_is_loaded_called++;
tt_int_op(family, OP_EQ, AF_INET);
@@ -1327,27 +1308,29 @@ NS(geoip_is_loaded)(sa_family_t family)
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, add_a1)
-
/*
* Structural test for routerset_add_unknown_ccs, that the "{a1}"
* country code is added to the list.
*/
-NS_DECL(country_t, geoip_get_country, (const char *country));
-NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+static country_t rset_add_unknown_ccs_add_a1_geoip_get_country(
+ const char *country);
+static int rset_add_unknown_ccs_add_a1_geoip_get_country_called = 0;
+static int rset_add_unknown_ccs_add_a1_geoip_is_loaded(sa_family_t family);
+static int rset_add_unknown_ccs_add_a1_geoip_is_loaded_called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_add_unknown_ccs_add_a1(void *arg)
{
routerset_t *set = routerset_new();
routerset_t **setp = &set;
int r;
(void)arg;
- NS_MOCK(geoip_get_country);
- NS_MOCK(geoip_is_loaded);
+ MOCK(geoip_get_country,
+ rset_add_unknown_ccs_add_a1_geoip_get_country);
+ MOCK(geoip_is_loaded,
+ rset_add_unknown_ccs_add_a1_geoip_is_loaded);
r = routerset_add_unknown_ccs(setp, 0);
@@ -1361,11 +1344,11 @@ NS(test_main)(void *arg)
}
country_t
-NS(geoip_get_country)(const char *country)
+rset_add_unknown_ccs_add_a1_geoip_get_country(const char *country)
{
int arg_is_qq, arg_is_a1;
- CALLED(geoip_get_country)++;
+ rset_add_unknown_ccs_add_a1_geoip_get_country_called++;
arg_is_qq = !strcmp(country, "??");
arg_is_a1 = !strcmp(country, "A1");
@@ -1380,9 +1363,9 @@ NS(geoip_get_country)(const char *country)
}
int
-NS(geoip_is_loaded)(sa_family_t family)
+rset_add_unknown_ccs_add_a1_geoip_is_loaded(sa_family_t family)
{
- CALLED(geoip_is_loaded)++;
+ rset_add_unknown_ccs_add_a1_geoip_is_loaded_called++;
tt_int_op(family, OP_EQ, AF_INET);
@@ -1390,15 +1373,12 @@ NS(geoip_is_loaded)(sa_family_t family)
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_contains_extendinfo
-
/*
* Functional test for routerset_contains_extendinfo.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_extendinfo(void *arg)
{
routerset_t *set = routerset_new();
extend_info_t ei;
@@ -1418,15 +1398,12 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_contains_router
-
/*
* Functional test for routerset_contains_router.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_router(void *arg)
{
routerset_t *set = routerset_new();
routerinfo_t ri;
@@ -1440,14 +1417,61 @@ NS(test_main)(void *arg)
ri.nickname = (char *)nickname;
r = routerset_contains_router(set, &ri, country);
-
tt_int_op(r, OP_EQ, 4);
+
done:
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_contains_routerstatus
+static void
+test_rset_contains_router_ipv4(void *arg)
+{
+ routerset_t *set;
+ routerinfo_t ri;
+ country_t country = 1;
+ int r;
+ const char *s;
+ (void) arg;
+
+ /* IPv4 address test. */
+ memset(&ri, 0, sizeof(ri));
+ set = routerset_new();
+ s = "10.0.0.1";
+ r = routerset_parse(set, s, "");
+ tor_addr_from_ipv4h(&ri.ipv4_addr, 0x0a000001);
+ ri.ipv4_orport = 1234;
+
+ r = routerset_contains_router(set, &ri, country);
+ tt_int_op(r, OP_EQ, 3);
+
+ done:
+ routerset_free(set);
+}
+
+static void
+test_rset_contains_router_ipv6(void *arg)
+{
+ routerset_t *set;
+ routerinfo_t ri;
+ country_t country = 1;
+ int r;
+ const char *s;
+ (void) arg;
+
+ /* IPv6 address test. */
+ memset(&ri, 0, sizeof(ri));
+ set = routerset_new();
+ s = "2600::1";
+ r = routerset_parse(set, s, "");
+ tor_addr_parse(&ri.ipv6_addr, "2600::1");
+ ri.ipv6_orport = 12345;
+
+ r = routerset_contains_router(set, &ri, country);
+ tt_int_op(r, OP_EQ, 3);
+
+ done:
+ routerset_free(set);
+}
/*
* Functional test for routerset_contains_routerstatus.
@@ -1458,7 +1482,7 @@ NS(test_main)(void *arg)
// a bit more or test a bit more.
static void
-NS(test_main)(void *arg)
+test_rset_contains_routerstatus(void *arg)
{
routerset_t *set = routerset_new();
routerstatus_t rs;
@@ -1479,46 +1503,41 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains_node, none)
-
/*
* Functional test for routerset_contains_node, when the node has no
* routerset or routerinfo.
*/
-static node_t NS(mock_node);
+static node_t rset_contains_none_mock_node;
static void
-NS(test_main)(void *arg)
+test_rset_contains_none(void *arg)
{
routerset_t *set = routerset_new();
int r;
(void)arg;
- memset(&NS(mock_node), 0, sizeof(NS(mock_node)));
- NS(mock_node).ri = NULL;
- NS(mock_node).rs = NULL;
+ memset(&rset_contains_none_mock_node, 0,
+ sizeof(rset_contains_none_mock_node));
+ rset_contains_none_mock_node.ri = NULL;
+ rset_contains_none_mock_node.rs = NULL;
- r = routerset_contains_node(set, &NS(mock_node));
+ r = routerset_contains_node(set, &rset_contains_none_mock_node);
tt_int_op(r, OP_EQ, 0);
done:
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains_node, routerstatus)
-
/*
* Functional test for routerset_contains_node, when the node has a
* routerset and no routerinfo.
*/
-static node_t NS(mock_node);
+static node_t rset_contains_rs_mock_node;
static void
-NS(test_main)(void *arg)
+test_rset_contains_rs(void *arg)
{
routerset_t *set = routerset_new();
int r;
@@ -1530,27 +1549,24 @@ NS(test_main)(void *arg)
strncpy(rs.nickname, nickname, sizeof(rs.nickname) - 1);
rs.nickname[sizeof(rs.nickname) - 1] = '\0';
- memset(&NS(mock_node), 0, sizeof(NS(mock_node)));
- NS(mock_node).ri = NULL;
- NS(mock_node).rs = &rs;
+ memset(&rset_contains_rs_mock_node, 0, sizeof(rset_contains_rs_mock_node));
+ rset_contains_rs_mock_node.ri = NULL;
+ rset_contains_rs_mock_node.rs = &rs;
- r = routerset_contains_node(set, &NS(mock_node));
+ r = routerset_contains_node(set, &rset_contains_rs_mock_node);
tt_int_op(r, OP_EQ, 4);
done:
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_contains_node, routerinfo)
-
/*
* Functional test for routerset_contains_node, when the node has no
* routerset and a routerinfo.
*/
static void
-NS(test_main)(void *arg)
+test_rset_contains_routerinfo(void *arg)
{
routerset_t *set = routerset_new();
int r;
@@ -1573,16 +1589,13 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, no_routerset)
-
/*
* Functional test for routerset_get_all_nodes, when routerset is NULL or
* the routerset list is NULL.
*/
static void
-NS(test_main)(void *arg)
+test_rset_get_all_no_routerset(void *arg)
{
smartlist_t *out = smartlist_new();
routerset_t *set = NULL;
@@ -1606,30 +1619,29 @@ NS(test_main)(void *arg)
smartlist_free(out);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list_with_no_nodes)
-
/*
* Structural test for routerset_get_all_nodes, when the routerset list
* is empty.
*/
-NS_DECL(const node_t *, node_get_by_nickname,
- (const char *nickname, unsigned flags));
-static const char *NS(mock_nickname);
+static const node_t * rset_get_all_l_no_nodes_node_get_by_nickname(
+ const char *nickname, unsigned flags);
+static int rset_get_all_l_no_nodes_node_get_by_nickname_called = 0;
+static const char *rset_get_all_l_no_nodes_mock_nickname;
static void
-NS(test_main)(void *arg)
+test_rset_get_all_l_no_nodes(void *arg)
{
smartlist_t *out = smartlist_new();
routerset_t *set = routerset_new();
int out_len;
(void)arg;
- NS_MOCK(node_get_by_nickname);
+ MOCK(node_get_by_nickname,
+ rset_get_all_l_no_nodes_node_get_by_nickname);
- NS(mock_nickname) = "foo";
- smartlist_add_strdup(set->list, NS(mock_nickname));
+ rset_get_all_l_no_nodes_mock_nickname = "foo";
+ smartlist_add_strdup(set->list, rset_get_all_l_no_nodes_mock_nickname);
routerset_get_all_nodes(out, set, NULL, 0);
out_len = smartlist_len(out);
@@ -1638,49 +1650,49 @@ NS(test_main)(void *arg)
routerset_free(set);
tt_int_op(out_len, OP_EQ, 0);
- tt_int_op(CALLED(node_get_by_nickname), OP_EQ, 1);
+ tt_int_op(rset_get_all_l_no_nodes_node_get_by_nickname_called, OP_EQ, 1);
done:
;
}
const node_t *
-NS(node_get_by_nickname)(const char *nickname, unsigned flags)
+rset_get_all_l_no_nodes_node_get_by_nickname(const char *nickname,
+ unsigned flags)
{
- CALLED(node_get_by_nickname)++;
- tt_str_op(nickname, OP_EQ, NS(mock_nickname));
+ rset_get_all_l_no_nodes_node_get_by_nickname_called++;
+ tt_str_op(nickname, OP_EQ, rset_get_all_l_no_nodes_mock_nickname);
tt_uint_op(flags, OP_EQ, 0);
done:
return NULL;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list_flag_not_running)
-
/*
* Structural test for routerset_get_all_nodes, with the running_only flag
* is set but the nodes are not running.
*/
-NS_DECL(const node_t *, node_get_by_nickname,
- (const char *nickname, unsigned flags));
-static const char *NS(mock_nickname);
-static node_t NS(mock_node);
+static const node_t * rset_get_all_l_not_running_node_get_by_nickname(
+ const char *nickname, unsigned flags);
+static int rset_get_all_l_not_running_node_get_by_nickname_called = 0;
+static const char *rset_get_all_l_not_running_mock_nickname;
+static node_t rset_get_all_l_not_running_mock_node;
static void
-NS(test_main)(void *arg)
+test_rset_get_all_l_not_running(void *arg)
{
smartlist_t *out = smartlist_new();
routerset_t *set = routerset_new();
int out_len;
(void)arg;
- NS_MOCK(node_get_by_nickname);
+ MOCK(node_get_by_nickname,
+ rset_get_all_l_not_running_node_get_by_nickname);
- NS(mock_node).is_running = 0;
- NS(mock_nickname) = "foo";
- smartlist_add_strdup(set->list, NS(mock_nickname));
+ rset_get_all_l_not_running_mock_node.is_running = 0;
+ rset_get_all_l_not_running_mock_nickname = "foo";
+ smartlist_add_strdup(set->list, rset_get_all_l_not_running_mock_nickname);
routerset_get_all_nodes(out, set, NULL, 1);
out_len = smartlist_len(out);
@@ -1689,37 +1701,36 @@ NS(test_main)(void *arg)
routerset_free(set);
tt_int_op(out_len, OP_EQ, 0);
- tt_int_op(CALLED(node_get_by_nickname), OP_EQ, 1);
+ tt_int_op(rset_get_all_l_not_running_node_get_by_nickname_called, OP_EQ, 1);
done:
;
}
const node_t *
-NS(node_get_by_nickname)(const char *nickname, unsigned flags)
+rset_get_all_l_not_running_node_get_by_nickname(const char *nickname,
+ unsigned flags)
{
- CALLED(node_get_by_nickname)++;
- tt_str_op(nickname, OP_EQ, NS(mock_nickname));
+ rset_get_all_l_not_running_node_get_by_nickname_called++;
+ tt_str_op(nickname, OP_EQ, rset_get_all_l_not_running_mock_nickname);
tt_int_op(flags, OP_EQ, 0);
done:
- return &NS(mock_node);
+ return &rset_get_all_l_not_running_mock_node;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list)
-
/*
* Structural test for routerset_get_all_nodes.
*/
-NS_DECL(const node_t *, node_get_by_nickname,
- (const char *nickname, unsigned flags));
-static char *NS(mock_nickname);
-static node_t NS(mock_node);
+static const node_t * rset_get_all_list_node_get_by_nickname(
+ const char *nickname, unsigned flags);
+static int rset_get_all_list_node_get_by_nickname_called = 0;
+static char *rset_get_all_list_mock_nickname;
+static node_t rset_get_all_list_mock_node;
static void
-NS(test_main)(void *arg)
+test_rset_get_all_list(void *arg)
{
smartlist_t *out = smartlist_new();
routerset_t *set = routerset_new();
@@ -1727,10 +1738,11 @@ NS(test_main)(void *arg)
node_t *ent;
(void)arg;
- NS_MOCK(node_get_by_nickname);
+ MOCK(node_get_by_nickname,
+ rset_get_all_list_node_get_by_nickname);
- NS(mock_nickname) = tor_strdup("foo");
- smartlist_add(set->list, NS(mock_nickname));
+ rset_get_all_list_mock_nickname = tor_strdup("foo");
+ smartlist_add(set->list, rset_get_all_list_mock_nickname);
routerset_get_all_nodes(out, set, NULL, 0);
out_len = smartlist_len(out);
@@ -1740,127 +1752,122 @@ NS(test_main)(void *arg)
routerset_free(set);
tt_int_op(out_len, OP_EQ, 1);
- tt_ptr_op(ent, OP_EQ, &NS(mock_node));
- tt_int_op(CALLED(node_get_by_nickname), OP_EQ, 1);
+ tt_ptr_op(ent, OP_EQ, &rset_get_all_list_mock_node);
+ tt_int_op(rset_get_all_list_node_get_by_nickname_called, OP_EQ, 1);
done:
;
}
const node_t *
-NS(node_get_by_nickname)(const char *nickname, unsigned flags)
+rset_get_all_list_node_get_by_nickname(const char *nickname, unsigned flags)
{
- CALLED(node_get_by_nickname)++;
- tt_str_op(nickname, OP_EQ, NS(mock_nickname));
+ rset_get_all_list_node_get_by_nickname_called++;
+ tt_str_op(nickname, OP_EQ, rset_get_all_list_mock_nickname);
tt_int_op(flags, OP_EQ, 0);
done:
- return &NS(mock_node);
+ return &rset_get_all_list_mock_node;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, nodelist_with_no_nodes)
-
/*
* Structural test for routerset_get_all_nodes, when the nodelist has no nodes.
*/
-NS_DECL(smartlist_t *, nodelist_get_list, (void));
-
-static smartlist_t *NS(mock_smartlist);
+static const smartlist_t * rset_get_all_n_no_nodes_nodelist_get_list(void);
+static int rset_get_all_n_no_nodes_nodelist_get_list_called = 0;
+static smartlist_t *rset_get_all_n_no_nodes_mock_smartlist;
static void
-NS(test_main)(void *arg)
+test_rset_get_all_n_no_nodes(void *arg)
{
routerset_t *set = routerset_new();
smartlist_t *out = smartlist_new();
int r;
(void)arg;
- NS_MOCK(nodelist_get_list);
+ MOCK(nodelist_get_list,
+ rset_get_all_n_no_nodes_nodelist_get_list);
smartlist_add_strdup(set->country_names, "{xx}");
- NS(mock_smartlist) = smartlist_new();
+ rset_get_all_n_no_nodes_mock_smartlist = smartlist_new();
routerset_get_all_nodes(out, set, NULL, 1);
r = smartlist_len(out);
routerset_free(set);
smartlist_free(out);
- smartlist_free(NS(mock_smartlist));
+ smartlist_free(rset_get_all_n_no_nodes_mock_smartlist);
tt_int_op(r, OP_EQ, 0);
- tt_int_op(CALLED(nodelist_get_list), OP_EQ, 1);
+ tt_int_op(rset_get_all_n_no_nodes_nodelist_get_list_called, OP_EQ, 1);
done:
;
}
-smartlist_t *
-NS(nodelist_get_list)(void)
+const smartlist_t *
+rset_get_all_n_no_nodes_nodelist_get_list(void)
{
- CALLED(nodelist_get_list)++;
+ rset_get_all_n_no_nodes_nodelist_get_list_called++;
- return NS(mock_smartlist);
+ return rset_get_all_n_no_nodes_mock_smartlist;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, nodelist_flag_not_running)
-
/*
* Structural test for routerset_get_all_nodes, with a non-list routerset
* the running_only flag is set, but the nodes are not running.
*/
-NS_DECL(smartlist_t *, nodelist_get_list, (void));
+static const smartlist_t * rset_get_all_n_not_running_nodelist_get_list(void);
+static int rset_get_all_n_not_running_nodelist_get_list_called = 0;
-static smartlist_t *NS(mock_smartlist);
-static node_t NS(mock_node);
+static smartlist_t *rset_get_all_n_not_running_mock_smartlist;
+static node_t rset_get_all_n_not_running_mock_node;
static void
-NS(test_main)(void *arg)
+test_rset_get_all_n_not_running(void *arg)
{
routerset_t *set = routerset_new();
smartlist_t *out = smartlist_new();
int r;
(void)arg;
- NS_MOCK(nodelist_get_list);
+ MOCK(nodelist_get_list,
+ rset_get_all_n_not_running_nodelist_get_list);
smartlist_add_strdup(set->country_names, "{xx}");
- NS(mock_smartlist) = smartlist_new();
- NS(mock_node).is_running = 0;
- smartlist_add(NS(mock_smartlist), (void *)&NS(mock_node));
+ rset_get_all_n_not_running_mock_smartlist = smartlist_new();
+ rset_get_all_n_not_running_mock_node.is_running = 0;
+ smartlist_add(rset_get_all_n_not_running_mock_smartlist,
+ (void *)&rset_get_all_n_not_running_mock_node);
routerset_get_all_nodes(out, set, NULL, 1);
r = smartlist_len(out);
routerset_free(set);
smartlist_free(out);
- smartlist_free(NS(mock_smartlist));
+ smartlist_free(rset_get_all_n_not_running_mock_smartlist);
tt_int_op(r, OP_EQ, 0);
- tt_int_op(CALLED(nodelist_get_list), OP_EQ, 1);
+ tt_int_op(rset_get_all_n_not_running_nodelist_get_list_called, OP_EQ, 1);
done:
;
}
-smartlist_t *
-NS(nodelist_get_list)(void)
+const smartlist_t *
+rset_get_all_n_not_running_nodelist_get_list(void)
{
- CALLED(nodelist_get_list)++;
+ rset_get_all_n_not_running_nodelist_get_list_called++;
- return NS(mock_smartlist);
+ return rset_get_all_n_not_running_mock_smartlist;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_subtract_nodes
-
/*
* Functional test for routerset_subtract_nodes.
*/
static void
-NS(test_main)(void *arg)
+test_rset_subtract_nodes(void *arg)
{
routerset_t *set = routerset_new();
smartlist_t *list = smartlist_new();
@@ -1885,15 +1892,12 @@ NS(test_main)(void *arg)
smartlist_free(list);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_subtract_nodes, null_routerset)
-
/*
* Functional test for routerset_subtract_nodes, with a NULL routerset.
*/
static void
-NS(test_main)(void *arg)
+test_rset_subtract_nodes_null_routerset(void *arg)
{
routerset_t *set = NULL;
smartlist_t *list = smartlist_new();
@@ -1915,15 +1919,12 @@ NS(test_main)(void *arg)
smartlist_free(list);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_to_string
-
/*
* Functional test for routerset_to_string.
*/
static void
-NS(test_main)(void *arg)
+test_rset_to_string(void *arg)
{
routerset_t *set = NULL;
char *s = NULL;
@@ -1960,15 +1961,12 @@ NS(test_main)(void *arg)
routerset_free(set);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_equal, empty_empty)
-
/*
* Functional test for routerset_equal, with both routersets empty.
*/
static void
-NS(test_main)(void *arg)
+test_rset_equal_empty_empty(void *arg)
{
routerset_t *a = routerset_new(), *b = routerset_new();
int r;
@@ -1984,15 +1982,12 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_equal, empty_not_empty)
-
/*
* Functional test for routerset_equal, with one routersets empty.
*/
static void
-NS(test_main)(void *arg)
+test_rset_equal_empty_not_empty(void *arg)
{
routerset_t *a = routerset_new(), *b = routerset_new();
int r;
@@ -2008,16 +2003,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_equal, differing_lengths)
-
/*
* Functional test for routerset_equal, with the routersets having
* differing lengths.
*/
static void
-NS(test_main)(void *arg)
+test_rset_equal_differing_lengths(void *arg)
{
routerset_t *a = routerset_new(), *b = routerset_new();
int r;
@@ -2035,16 +2027,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_equal, unequal)
-
/*
* Functional test for routerset_equal, with the routersets being
* different.
*/
static void
-NS(test_main)(void *arg)
+test_rset_equal_unequal(void *arg)
{
routerset_t *a = routerset_new(), *b = routerset_new();
int r;
@@ -2061,16 +2050,13 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_equal, equal)
-
/*
* Functional test for routerset_equal, with the routersets being
* equal.
*/
static void
-NS(test_main)(void *arg)
+test_rset_equal_equal(void *arg)
{
routerset_t *a = routerset_new(), *b = routerset_new();
int r;
@@ -2087,147 +2073,180 @@ NS(test_main)(void *arg)
;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(routerset_free, null_routerset)
-
/*
* Structural test for routerset_free, where the routerset is NULL.
*/
-NS_DECL(void, smartlist_free_, (smartlist_t *sl));
+static void rset_free_null_routerset_smartlist_free_(smartlist_t *sl);
+static int rset_free_null_routerset_smartlist_free__called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_free_null_routerset(void *arg)
{
(void)arg;
- NS_MOCK(smartlist_free_);
+ MOCK(smartlist_free_,
+ rset_free_null_routerset_smartlist_free_);
routerset_free_(NULL);
- tt_int_op(CALLED(smartlist_free_), OP_EQ, 0);
+ tt_int_op(rset_free_null_routerset_smartlist_free__called, OP_EQ, 0);
done:
;
}
void
-NS(smartlist_free_)(smartlist_t *s)
+rset_free_null_routerset_smartlist_free_(smartlist_t *s)
{
(void)s;
- CALLED(smartlist_free_)++;
+ rset_free_null_routerset_smartlist_free__called++;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE routerset_free
-
/*
* Structural test for routerset_free.
*/
-NS_DECL(void, smartlist_free_, (smartlist_t *sl));
-NS_DECL(void, strmap_free_,(strmap_t *map, void (*free_val)(void*)));
-NS_DECL(void, digestmap_free_, (digestmap_t *map, void (*free_val)(void*)));
+static void rset_free_smartlist_free_(smartlist_t *sl);
+static int rset_free_smartlist_free__called = 0;
+static void rset_free_strmap_free_(strmap_t *map, void (*free_val)(void*));
+static int rset_free_strmap_free__called = 0;
+static void rset_free_digestmap_free_(digestmap_t *map,
+ void (*free_val)(void*));
+static int rset_free_digestmap_free__called = 0;
static void
-NS(test_main)(void *arg)
+test_rset_free(void *arg)
{
routerset_t *routerset = routerset_new();
(void)arg;
- NS_MOCK(smartlist_free_);
- NS_MOCK(strmap_free_);
- NS_MOCK(digestmap_free_);
+ MOCK(smartlist_free_,
+ rset_free_smartlist_free_);
+ MOCK(strmap_free_,
+ rset_free_strmap_free_);
+ MOCK(digestmap_free_,
+ rset_free_digestmap_free_);
routerset_free(routerset);
- tt_int_op(CALLED(smartlist_free_), OP_NE, 0);
- tt_int_op(CALLED(strmap_free_), OP_NE, 0);
- tt_int_op(CALLED(digestmap_free_), OP_NE, 0);
+ tt_int_op(rset_free_smartlist_free__called, OP_NE, 0);
+ tt_int_op(rset_free_strmap_free__called, OP_NE, 0);
+ tt_int_op(rset_free_digestmap_free__called, OP_NE, 0);
done:
;
}
void
-NS(smartlist_free_)(smartlist_t *s)
+rset_free_smartlist_free_(smartlist_t *s)
{
- CALLED(smartlist_free_)++;
+ rset_free_smartlist_free__called++;
smartlist_free___real(s);
}
void
-NS(strmap_free_)(strmap_t *map, void (*free_val)(void*))
+rset_free_strmap_free_(strmap_t *map, void (*free_val)(void*))
{
- CALLED(strmap_free_)++;
+ rset_free_strmap_free__called++;
strmap_free___real(map, free_val);
}
void
-NS(digestmap_free_)(digestmap_t *map, void (*free_val)(void*))
+rset_free_digestmap_free_(digestmap_t *map, void (*free_val)(void*))
{
- CALLED(digestmap_free_)++;
+ rset_free_digestmap_free__called++;
digestmap_free___real(map, free_val);
}
-#undef NS_SUBMODULE
-
struct testcase_t routerset_tests[] = {
- TEST_CASE(routerset_new),
- TEST_CASE(routerset_get_countryname),
- TEST_CASE(routerset_is_list),
- TEST_CASE(routerset_needs_geoip),
- TEST_CASE(routerset_is_empty),
- TEST_CASE_ASPECT(routerset_contains, null_set_or_null_set_list),
- TEST_CASE_ASPECT(routerset_contains, set_and_nickname),
- TEST_CASE_ASPECT(routerset_contains, set_and_null_nickname),
- TEST_CASE_ASPECT(routerset_contains, set_and_no_nickname),
- TEST_CASE_ASPECT(routerset_contains, set_and_digest),
- TEST_CASE_ASPECT(routerset_contains, set_and_no_digest),
- TEST_CASE_ASPECT(routerset_contains, set_and_null_digest),
- TEST_CASE_ASPECT(routerset_contains, set_and_addr),
- TEST_CASE_ASPECT(routerset_contains, set_and_no_addr),
- TEST_CASE_ASPECT(routerset_contains, set_and_null_addr),
- TEST_CASE_ASPECT(routerset_contains, countries_no_geoip),
- TEST_CASE_ASPECT(routerset_contains, countries_geoip),
- TEST_CASE_ASPECT(routerset_add_unknown_ccs, only_flag_and_no_ccs),
- TEST_CASE_ASPECT(routerset_add_unknown_ccs, creates_set),
- TEST_CASE_ASPECT(routerset_add_unknown_ccs, add_unknown),
- TEST_CASE_ASPECT(routerset_add_unknown_ccs, add_a1),
- TEST_CASE(routerset_contains_extendinfo),
- TEST_CASE(routerset_contains_router),
- TEST_CASE(routerset_contains_routerstatus),
- TEST_CASE_ASPECT(routerset_contains_node, none),
- TEST_CASE_ASPECT(routerset_contains_node, routerinfo),
- TEST_CASE_ASPECT(routerset_contains_node, routerstatus),
- TEST_CASE_ASPECT(routerset_get_all_nodes, no_routerset),
- TEST_CASE_ASPECT(routerset_get_all_nodes, list_with_no_nodes),
- TEST_CASE_ASPECT(routerset_get_all_nodes, list_flag_not_running),
- TEST_CASE_ASPECT(routerset_get_all_nodes, list),
- TEST_CASE_ASPECT(routerset_get_all_nodes, nodelist_with_no_nodes),
- TEST_CASE_ASPECT(routerset_get_all_nodes, nodelist_flag_not_running),
- TEST_CASE_ASPECT(routerset_refresh_counties, geoip_not_loaded),
- TEST_CASE_ASPECT(routerset_refresh_counties, no_countries),
- TEST_CASE_ASPECT(routerset_refresh_counties, one_valid_country),
- TEST_CASE_ASPECT(routerset_refresh_counties, one_invalid_country),
- TEST_CASE_ASPECT(routerset_union, source_bad),
- TEST_CASE_ASPECT(routerset_union, one),
- TEST_CASE_ASPECT(routerset_parse, malformed),
- TEST_CASE_ASPECT(routerset_parse, valid_hexdigest),
- TEST_CASE_ASPECT(routerset_parse, valid_nickname),
- TEST_CASE_ASPECT(routerset_parse, get_countryname),
- TEST_CASE_ASPECT(routerset_parse, policy_wildcard),
- TEST_CASE_ASPECT(routerset_parse, policy_ipv4),
- TEST_CASE_ASPECT(routerset_parse, policy_ipv6),
- TEST_CASE(routerset_subtract_nodes),
- TEST_CASE_ASPECT(routerset_subtract_nodes, null_routerset),
- TEST_CASE(routerset_to_string),
- TEST_CASE_ASPECT(routerset_equal, empty_empty),
- TEST_CASE_ASPECT(routerset_equal, empty_not_empty),
- TEST_CASE_ASPECT(routerset_equal, differing_lengths),
- TEST_CASE_ASPECT(routerset_equal, unequal),
- TEST_CASE_ASPECT(routerset_equal, equal),
- TEST_CASE_ASPECT(routerset_free, null_routerset),
- TEST_CASE(routerset_free),
+ { "new", test_rset_new, TT_FORK, NULL, NULL },
+ { "get_countryname", test_rset_get_countryname, TT_FORK, NULL, NULL },
+ { "is_list", test_rset_is_list, TT_FORK, NULL, NULL },
+ { "needs_geoip", test_rset_needs_geoip, TT_FORK, NULL, NULL },
+ { "is_empty", test_rset_is_empty, TT_FORK, NULL, NULL },
+ { "contains_null_set_or_list", test_rset_contains_null_set_or_list,
+ TT_FORK, NULL, NULL },
+ { "contains_nickname", test_rset_contains_nickname, TT_FORK, NULL, NULL },
+ { "contains_null_nickname", test_rset_contains_null_nickname,
+ TT_FORK, NULL, NULL },
+ { "contains_no_nickname", test_rset_contains_no_nickname,
+ TT_FORK, NULL, NULL },
+ { "contains_digest", test_rset_contains_digest, TT_FORK, NULL, NULL },
+ { "contains_no_digest", test_rset_contains_no_digest, TT_FORK, NULL, NULL },
+ { "contains_null_digest", test_rset_contains_null_digest,
+ TT_FORK, NULL, NULL },
+ { "contains_addr", test_rset_contains_addr, TT_FORK, NULL, NULL },
+ { "contains_no_addr", test_rset_contains_no_addr, TT_FORK, NULL, NULL },
+ { "contains_null_addr", test_rset_contains_null_addr, TT_FORK, NULL, NULL },
+ { "contains_countries_no_geoip", test_rset_countries_no_geoip,
+ TT_FORK, NULL, NULL },
+ { "contains_countries_geoip", test_rset_countries_geoip,
+ TT_FORK, NULL, NULL },
+ { "add_unknown_ccs_only_flag", test_rset_add_unknown_ccs_only_flag,
+ TT_FORK, NULL, NULL },
+ { "add_unknown_ccs_creates_set", test_rset_add_unknown_ccs_creates_set,
+ TT_FORK, NULL, NULL },
+ { "add_unknown_ccs_add_unknown", test_rset_add_unknown_ccs_add_unknown,
+ TT_FORK, NULL, NULL },
+ { "add_unknown_ccs_add_a1", test_rset_add_unknown_ccs_add_a1,
+ TT_FORK, NULL, NULL },
+ { "contains_extendinfo", test_rset_contains_extendinfo,
+ TT_FORK, NULL, NULL },
+ { "contains_router", test_rset_contains_router, TT_FORK, NULL, NULL },
+ { "contains_router_ipv4", test_rset_contains_router_ipv4,
+ TT_FORK, NULL, NULL },
+ { "contains_router_ipv6", test_rset_contains_router_ipv6,
+ TT_FORK, NULL, NULL },
+ { "contains_routerstatus", test_rset_contains_routerstatus,
+ TT_FORK, NULL, NULL },
+ { "contains_none", test_rset_contains_none, TT_FORK, NULL, NULL },
+ { "contains_routerinfo", test_rset_contains_routerinfo,
+ TT_FORK, NULL, NULL },
+ { "contains_rs", test_rset_contains_rs, TT_FORK, NULL, NULL },
+ { "get_all_no_routerset", test_rset_get_all_no_routerset,
+ TT_FORK, NULL, NULL },
+ { "get_all_l_no_nodes", test_rset_get_all_l_no_nodes, TT_FORK, NULL, NULL },
+ { "get_all_l_not_running", test_rset_get_all_l_not_running,
+ TT_FORK, NULL, NULL },
+ { "get_all_list", test_rset_get_all_list, TT_FORK, NULL, NULL },
+ { "get_all_n_no_nodes", test_rset_get_all_n_no_nodes, TT_FORK, NULL, NULL },
+ { "get_all_n_not_running", test_rset_get_all_n_not_running,
+ TT_FORK, NULL, NULL },
+ { "refresh_geoip_not_loaded", test_rset_refresh_geoip_not_loaded,
+ TT_FORK, NULL, NULL },
+ { "refresh_no_countries", test_rset_refresh_no_countries,
+ TT_FORK, NULL, NULL },
+ { "refresh_one_valid_country", test_rset_refresh_one_valid_country,
+ TT_FORK, NULL, NULL },
+ { "refresh_one_invalid_country", test_rset_refresh_one_invalid_country,
+ TT_FORK, NULL, NULL },
+ { "union_source_bad", test_rset_union_source_bad, TT_FORK, NULL, NULL },
+ { "union_one", test_rset_union_one, TT_FORK, NULL, NULL },
+ { "parse_malformed", test_rset_parse_malformed, TT_FORK, NULL, NULL },
+ { "parse_valid_hexdigest", test_rset_parse_valid_hexdigest,
+ TT_FORK, NULL, NULL },
+ { "parse_valid_nickname", test_rset_parse_valid_nickname,
+ TT_FORK, NULL, NULL },
+ { "parse_get_countryname", test_rset_parse_get_countryname,
+ TT_FORK, NULL, NULL },
+ { "parse_policy_wildcard", test_rset_parse_policy_wildcard,
+ TT_FORK, NULL, NULL },
+ { "parse_policy_ipv4", test_rset_parse_policy_ipv4, TT_FORK, NULL, NULL },
+ { "parse_policy_ipv6", test_rset_parse_policy_ipv6, TT_FORK, NULL, NULL },
+ { "subtract_nodes", test_rset_subtract_nodes, TT_FORK, NULL, NULL },
+ { "subtract_nodes_null_routerset", test_rset_subtract_nodes_null_routerset,
+ TT_FORK, NULL, NULL },
+ { "to_string", test_rset_to_string, TT_FORK, NULL, NULL },
+ { "equal_empty_empty", test_rset_equal_empty_empty, TT_FORK, NULL, NULL },
+ { "equal_empty_not_empty", test_rset_equal_empty_not_empty,
+ TT_FORK, NULL, NULL },
+ { "equal_differing_lengths", test_rset_equal_differing_lengths,
+ TT_FORK, NULL, NULL },
+ { "equal_unequal", test_rset_equal_unequal, TT_FORK, NULL, NULL },
+ { "equal_equal", test_rset_equal_equal, TT_FORK, NULL, NULL },
+ { "free_null_routerset", test_rset_free_null_routerset,
+ TT_FORK, NULL, NULL },
+ { "free", test_rset_free, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh
index 00b3e88d37..804d2ada36 100755
--- a/src/test/test_rust.sh
+++ b/src/test/test_rust.sh
@@ -14,11 +14,12 @@ rustc_host=$(rustc -vV | grep host | sed 's/host: //')
for cargo_toml_dir in "${abs_top_srcdir:-../../..}"/src/rust/*; do
if [ -e "${cargo_toml_dir}/Cargo.toml" ]; then
+ # shellcheck disable=SC2086
cd "${abs_top_builddir:-../../..}/src/rust" && \
CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \
- "${CARGO:-cargo}" test ${CARGO_ONLINE-"--frozen"} \
+ "${CARGO:-cargo}" test "${CARGO_ONLINE-'--frozen'}" \
--features "test_linking_hack" \
- --target $rustc_host \
+ --target "$rustc_host" \
${EXTRA_CARGO_OPTIONS} \
--manifest-path "${cargo_toml_dir}/Cargo.toml" || exitcode=1
fi
diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c
index bf9c6a49cd..9ec15948e8 100644
--- a/src/test/test_scheduler.c
+++ b/src/test/test_scheduler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -6,8 +6,8 @@
#include <math.h>
#define SCHEDULER_KIST_PRIVATE
-#define TOR_CHANNEL_INTERNAL_
-#define CHANNEL_PRIVATE_
+#define CHANNEL_OBJECT_PRIVATE
+#define CHANNEL_FILE_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
#include "lib/evloop/compat_libevent.h"
@@ -15,7 +15,7 @@
#include "core/or/channeltls.h"
#include "core/mainloop/connection.h"
#include "feature/nodelist/networkstatus.h"
-#define SCHEDULER_PRIVATE_
+#define SCHEDULER_PRIVATE
#include "core/or/scheduler.h"
/* Test suite stuff */
@@ -848,8 +848,8 @@ test_scheduler_initfree(void *arg)
{
(void)arg;
- tt_ptr_op(channels_pending, ==, NULL);
- tt_ptr_op(run_sched_ev, ==, NULL);
+ tt_ptr_op(channels_pending, OP_EQ, NULL);
+ tt_ptr_op(run_sched_ev, OP_EQ, NULL);
MOCK(get_options, mock_get_options);
set_scheduler_options(SCHEDULER_KIST);
@@ -858,17 +858,17 @@ test_scheduler_initfree(void *arg)
scheduler_init();
- tt_ptr_op(channels_pending, !=, NULL);
- tt_ptr_op(run_sched_ev, !=, NULL);
+ tt_ptr_op(channels_pending, OP_NE, NULL);
+ tt_ptr_op(run_sched_ev, OP_NE, NULL);
/* We have specified nothing in the torrc and there's no consensus so the
* KIST scheduler is what should be in use */
- tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
- tt_int_op(sched_run_interval, ==, 10);
+ tt_ptr_op(the_scheduler, OP_EQ, get_kist_scheduler());
+ tt_int_op(sched_run_interval, OP_EQ, 10);
scheduler_free_all();
- tt_ptr_op(channels_pending, ==, NULL);
- tt_ptr_op(run_sched_ev, ==, NULL);
+ tt_ptr_op(channels_pending, OP_EQ, NULL);
+ tt_ptr_op(run_sched_ev, OP_EQ, NULL);
done:
UNMOCK(get_options);
@@ -890,11 +890,11 @@ test_scheduler_can_use_kist(void *arg)
res_should = scheduler_can_use_kist();
res_freq = kist_scheduler_run_interval();
#ifdef HAVE_KIST_SUPPORT
- tt_int_op(res_should, ==, 1);
+ tt_int_op(res_should, OP_EQ, 1);
#else /* HAVE_KIST_SUPPORT */
- tt_int_op(res_should, ==, 0);
+ tt_int_op(res_should, OP_EQ, 0);
#endif /* HAVE_KIST_SUPPORT */
- tt_int_op(res_freq, ==, 1234);
+ tt_int_op(res_freq, OP_EQ, 1234);
/* Test defer to consensus, but no consensus available */
clear_options();
@@ -902,11 +902,11 @@ test_scheduler_can_use_kist(void *arg)
res_should = scheduler_can_use_kist();
res_freq = kist_scheduler_run_interval();
#ifdef HAVE_KIST_SUPPORT
- tt_int_op(res_should, ==, 1);
+ tt_int_op(res_should, OP_EQ, 1);
#else /* HAVE_KIST_SUPPORT */
- tt_int_op(res_should, ==, 0);
+ tt_int_op(res_should, OP_EQ, 0);
#endif /* HAVE_KIST_SUPPORT */
- tt_int_op(res_freq, ==, 10);
+ tt_int_op(res_freq, OP_EQ, 10);
/* Test defer to consensus, and kist consensus available */
MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
@@ -915,11 +915,11 @@ test_scheduler_can_use_kist(void *arg)
res_should = scheduler_can_use_kist();
res_freq = kist_scheduler_run_interval();
#ifdef HAVE_KIST_SUPPORT
- tt_int_op(res_should, ==, 1);
+ tt_int_op(res_should, OP_EQ, 1);
#else /* HAVE_KIST_SUPPORT */
- tt_int_op(res_should, ==, 0);
+ tt_int_op(res_should, OP_EQ, 0);
#endif /* HAVE_KIST_SUPPORT */
- tt_int_op(res_freq, ==, 12);
+ tt_int_op(res_freq, OP_EQ, 12);
UNMOCK(networkstatus_get_param);
/* Test defer to consensus, and vanilla consensus available */
@@ -928,8 +928,8 @@ test_scheduler_can_use_kist(void *arg)
mocked_options.KISTSchedRunInterval = 0;
res_should = scheduler_can_use_kist();
res_freq = kist_scheduler_run_interval();
- tt_int_op(res_should, ==, 0);
- tt_int_op(res_freq, ==, 0);
+ tt_int_op(res_should, OP_EQ, 0);
+ tt_int_op(res_freq, OP_EQ, 0);
UNMOCK(networkstatus_get_param);
done:
@@ -956,7 +956,7 @@ test_scheduler_ns_changed(void *arg)
set_scheduler_options(SCHEDULER_KIST);
set_scheduler_options(SCHEDULER_VANILLA);
- tt_ptr_op(the_scheduler, ==, NULL);
+ tt_ptr_op(the_scheduler, OP_EQ, NULL);
/* Change from vanilla to kist via consensus */
the_scheduler = get_vanilla_scheduler();
@@ -964,9 +964,9 @@ test_scheduler_ns_changed(void *arg)
scheduler_notify_networkstatus_changed();
UNMOCK(networkstatus_get_param);
#ifdef HAVE_KIST_SUPPORT
- tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_kist_scheduler());
#else
- tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
#endif
/* Change from kist to vanilla via consensus */
@@ -974,7 +974,7 @@ test_scheduler_ns_changed(void *arg)
MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
scheduler_notify_networkstatus_changed();
UNMOCK(networkstatus_get_param);
- tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
/* Doesn't change when using KIST */
the_scheduler = get_kist_scheduler();
@@ -982,9 +982,9 @@ test_scheduler_ns_changed(void *arg)
scheduler_notify_networkstatus_changed();
UNMOCK(networkstatus_get_param);
#ifdef HAVE_KIST_SUPPORT
- tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_kist_scheduler());
#else
- tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
#endif
/* Doesn't change when using vanilla */
@@ -992,7 +992,7 @@ test_scheduler_ns_changed(void *arg)
MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
scheduler_notify_networkstatus_changed();
UNMOCK(networkstatus_get_param);
- tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+ tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
done:
UNMOCK(get_options);
diff --git a/src/test/test_sendme.c b/src/test/test_sendme.c
new file mode 100644
index 0000000000..b34c7ae143
--- /dev/null
+++ b/src/test/test_sendme.c
@@ -0,0 +1,365 @@
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Unit tests for handling different kinds of relay cell */
+
+#define CIRCUITLIST_PRIVATE
+#define NETWORKSTATUS_PRIVATE
+#define SENDME_PRIVATE
+#define RELAY_PRIVATE
+
+#include "core/or/circuit_st.h"
+#include "core/or/or_circuit_st.h"
+#include "core/or/origin_circuit_st.h"
+#include "core/or/circuitlist.h"
+#include "core/or/relay.h"
+#include "core/or/sendme.h"
+
+#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/networkstatus_st.h"
+
+#include "lib/crypt_ops/crypto_digest.h"
+
+#include "test/test.h"
+#include "test/log_test_helpers.h"
+
+static void
+setup_mock_consensus(void)
+{
+ current_md_consensus = current_ns_consensus =
+ tor_malloc_zero(sizeof(networkstatus_t));
+ current_md_consensus->net_params = smartlist_new();
+ current_md_consensus->routerstatus_list = smartlist_new();
+}
+
+static void
+free_mock_consensus(void)
+{
+ SMARTLIST_FOREACH(current_md_consensus->routerstatus_list, void *, r,
+ tor_free(r));
+ smartlist_free(current_md_consensus->routerstatus_list);
+ smartlist_free(current_ns_consensus->net_params);
+ tor_free(current_ns_consensus);
+}
+
+static void
+test_v1_record_digest(void *arg)
+{
+ or_circuit_t *or_circ = NULL;
+ circuit_t *circ = NULL;
+
+ (void) arg;
+
+ /* Create our dummy circuit. */
+ or_circ = or_circuit_new(1, NULL);
+ /* Points it to the OR circuit now. */
+ circ = TO_CIRCUIT(or_circ);
+
+ /* The package window has to be a multiple of CIRCWINDOW_INCREMENT minus 1
+ * in order to catch the CIRCWINDOW_INCREMENT-nth cell. Try something that
+ * shouldn't be noted. */
+ circ->package_window = CIRCWINDOW_INCREMENT;
+ sendme_record_cell_digest_on_circ(circ, NULL);
+ tt_assert(!circ->sendme_last_digests);
+
+ /* This should work now. Package window at CIRCWINDOW_INCREMENT + 1. */
+ circ->package_window++;
+ sendme_record_cell_digest_on_circ(circ, NULL);
+ tt_assert(circ->sendme_last_digests);
+ tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
+
+ /* Next cell in the package window shouldn't do anything. */
+ circ->package_window++;
+ sendme_record_cell_digest_on_circ(circ, NULL);
+ tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
+
+ /* The next CIRCWINDOW_INCREMENT should add one more digest. */
+ circ->package_window = (CIRCWINDOW_INCREMENT * 2) + 1;
+ sendme_record_cell_digest_on_circ(circ, NULL);
+ tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 2);
+
+ done:
+ circuit_free_(circ);
+}
+
+static void
+test_v1_consensus_params(void *arg)
+{
+ (void) arg;
+
+ setup_mock_consensus();
+ tt_assert(current_md_consensus);
+
+ /* Both zeroes. */
+ smartlist_add(current_md_consensus->net_params,
+ (void *) "sendme_emit_min_version=0");
+ smartlist_add(current_md_consensus->net_params,
+ (void *) "sendme_accept_min_version=0");
+ tt_int_op(get_emit_min_version(), OP_EQ, 0);
+ tt_int_op(get_accept_min_version(), OP_EQ, 0);
+ smartlist_clear(current_md_consensus->net_params);
+
+ /* Both ones. */
+ smartlist_add(current_md_consensus->net_params,
+ (void *) "sendme_emit_min_version=1");
+ smartlist_add(current_md_consensus->net_params,
+ (void *) "sendme_accept_min_version=1");
+ tt_int_op(get_emit_min_version(), OP_EQ, 1);
+ tt_int_op(get_accept_min_version(), OP_EQ, 1);
+ smartlist_clear(current_md_consensus->net_params);
+
+ /* Different values from each other. */
+ smartlist_add(current_md_consensus->net_params,
+ (void *) "sendme_emit_min_version=1");
+ smartlist_add(current_md_consensus->net_params,
+ (void *) "sendme_accept_min_version=0");
+ tt_int_op(get_emit_min_version(), OP_EQ, 1);
+ tt_int_op(get_accept_min_version(), OP_EQ, 0);
+ smartlist_clear(current_md_consensus->net_params);
+
+ /* Validate is the cell version is coherent with our internal default value
+ * and the one in the consensus. */
+ smartlist_add(current_md_consensus->net_params,
+ (void *) "sendme_accept_min_version=1");
+ /* Minimum acceptable value is 1. */
+ tt_int_op(cell_version_can_be_handled(1), OP_EQ, true);
+ /* Minimum acceptable value is 1 so a cell version of 0 is refused. */
+ tt_int_op(cell_version_can_be_handled(0), OP_EQ, false);
+
+ done:
+ free_mock_consensus();
+}
+
+static void
+test_v1_build_cell(void *arg)
+{
+ uint8_t payload[RELAY_PAYLOAD_SIZE], digest[DIGEST_LEN];
+ ssize_t ret;
+ crypto_digest_t *cell_digest = NULL;
+ or_circuit_t *or_circ = NULL;
+ circuit_t *circ = NULL;
+
+ (void) arg;
+
+ or_circ = or_circuit_new(1, NULL);
+ circ = TO_CIRCUIT(or_circ);
+ circ->sendme_last_digests = smartlist_new();
+
+ cell_digest = crypto_digest_new();
+ tt_assert(cell_digest);
+ crypto_digest_add_bytes(cell_digest, "AAAAAAAAAAAAAAAAAAAA", 20);
+ crypto_digest_get_digest(cell_digest, (char *) digest, sizeof(digest));
+ smartlist_add(circ->sendme_last_digests, tor_memdup(digest, sizeof(digest)));
+
+ /* SENDME v1 payload is 3 bytes + 20 bytes digest. See spec. */
+ ret = build_cell_payload_v1(digest, payload);
+ tt_int_op(ret, OP_EQ, 23);
+
+ /* Validation. */
+
+ /* An empty payload means SENDME version 0 thus valid. */
+ tt_int_op(sendme_is_valid(circ, payload, 0), OP_EQ, true);
+ /* Current phoney digest should have been popped. */
+ tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
+
+ /* An unparseable cell means invalid. */
+ setup_full_capture_of_logs(LOG_INFO);
+ tt_int_op(sendme_is_valid(circ, (const uint8_t *) "A", 1), OP_EQ, false);
+ expect_log_msg_containing("Unparseable SENDME cell received. "
+ "Closing circuit.");
+ teardown_capture_of_logs();
+
+ /* No cell digest recorded for this. */
+ setup_full_capture_of_logs(LOG_INFO);
+ tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, false);
+ expect_log_msg_containing("We received a SENDME but we have no cell digests "
+ "to match. Closing circuit.");
+ teardown_capture_of_logs();
+
+ /* Note the wrong digest in the circuit, cell should fail validation. */
+ circ->package_window = CIRCWINDOW_INCREMENT + 1;
+ sendme_record_cell_digest_on_circ(circ, NULL);
+ tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
+ setup_full_capture_of_logs(LOG_INFO);
+ tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, false);
+ /* After a validation, the last digests is always popped out. */
+ tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
+ expect_log_msg_containing("SENDME v1 cell digest do not match.");
+ teardown_capture_of_logs();
+
+ /* Record the cell digest into the circuit, cell should validate. */
+ memcpy(or_circ->crypto.sendme_digest, digest, sizeof(digest));
+ circ->package_window = CIRCWINDOW_INCREMENT + 1;
+ sendme_record_cell_digest_on_circ(circ, NULL);
+ tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
+ tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, true);
+ /* After a validation, the last digests is always popped out. */
+ tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
+
+ done:
+ crypto_digest_free(cell_digest);
+ circuit_free_(circ);
+}
+
+static void
+test_cell_payload_pad(void *arg)
+{
+ size_t pad_offset, payload_len, expected_offset;
+
+ (void) arg;
+
+ /* Offset should be 0, not enough room for padding. */
+ payload_len = RELAY_PAYLOAD_SIZE;
+ pad_offset = get_pad_cell_offset(payload_len);
+ tt_int_op(pad_offset, OP_EQ, 0);
+ tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
+
+ /* Still no room because we keep 4 extra bytes. */
+ pad_offset = get_pad_cell_offset(payload_len - 4);
+ tt_int_op(pad_offset, OP_EQ, 0);
+ tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
+
+ /* We should have 1 byte of padding. Meaning, the offset should be the
+ * CELL_PAYLOAD_SIZE minus 1 byte. */
+ expected_offset = CELL_PAYLOAD_SIZE - 1;
+ pad_offset = get_pad_cell_offset(payload_len - 5);
+ tt_int_op(pad_offset, OP_EQ, expected_offset);
+ tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
+
+ /* Now some arbitrary small payload length. The cell size is header + 10 +
+ * extra 4 bytes we keep so the offset should be there. */
+ expected_offset = RELAY_HEADER_SIZE + 10 + 4;
+ pad_offset = get_pad_cell_offset(10);
+ tt_int_op(pad_offset, OP_EQ, expected_offset);
+ tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
+
+ /* Data length of 0. */
+ expected_offset = RELAY_HEADER_SIZE + 4;
+ pad_offset = get_pad_cell_offset(0);
+ tt_int_op(pad_offset, OP_EQ, expected_offset);
+ tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
+
+ done:
+ ;
+}
+
+static void
+test_cell_version_validation(void *arg)
+{
+ (void) arg;
+
+ /* We currently only support up to SENDME_MAX_SUPPORTED_VERSION so we are
+ * going to test the boundaries there. */
+
+ tt_assert(cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION));
+
+ /* Version below our supported should pass. */
+ tt_assert(cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION - 1));
+
+ /* Extra version from our supported should fail. */
+ tt_assert(!cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION + 1));
+
+ /* Simple check for version 0. */
+ tt_assert(cell_version_can_be_handled(0));
+
+ /* We MUST handle the default cell version that we emit or accept. */
+ tt_assert(cell_version_can_be_handled(SENDME_EMIT_MIN_VERSION_DEFAULT));
+ tt_assert(cell_version_can_be_handled(SENDME_ACCEPT_MIN_VERSION_DEFAULT));
+
+ done:
+ ;
+}
+
+/* check our decisions about how much stuff to put into relay cells. */
+static void
+test_package_payload_len(void *arg)
+{
+ (void)arg;
+ /* this is not a real circuit: it only has the fields needed for this
+ * test. */
+ circuit_t *c = tor_malloc_zero(sizeof(circuit_t));
+
+ /* check initial conditions. */
+ circuit_reset_sendme_randomness(c);
+ tt_assert(! c->have_sent_sufficiently_random_cell);
+ tt_int_op(c->send_randomness_after_n_cells, OP_GE, CIRCWINDOW_INCREMENT / 2);
+ tt_int_op(c->send_randomness_after_n_cells, OP_LT, CIRCWINDOW_INCREMENT);
+
+ /* We have a bunch of cells before we need to send randomness, so the first
+ * few can be packaged full. */
+ int initial = c->send_randomness_after_n_cells;
+ size_t n = connection_edge_get_inbuf_bytes_to_package(10000, 0, c);
+ tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n);
+ n = connection_edge_get_inbuf_bytes_to_package(95000, 1, c);
+ tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n);
+ tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2);
+
+ /* If package_partial isn't set, we won't package a partially full cell at
+ * all. */
+ n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 0, c);
+ tt_int_op(n, OP_EQ, 0);
+ /* no change in our state, since nothing was sent. */
+ tt_assert(! c->have_sent_sufficiently_random_cell);
+ tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2);
+
+ /* If package_partial is set and the partial cell is not going to have
+ * _enough_ randomness, we package it, but we don't consider ourselves to
+ * have sent a sufficiently random cell. */
+ n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 1, c);
+ tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE-1);
+ tt_assert(! c->have_sent_sufficiently_random_cell);
+ tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 3);
+
+ /* Make sure we set have_set_sufficiently_random_cell as appropriate. */
+ n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-64, 1, c);
+ tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE-64);
+ tt_assert(c->have_sent_sufficiently_random_cell);
+ tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 4);
+
+ /* Now let's look at what happens when we get down to zero. Since we have
+ * sent a sufficiently random cell, we will not force this one to have a gap.
+ */
+ c->send_randomness_after_n_cells = 0;
+ n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c);
+ tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE);
+ /* Now these will be reset. */
+ tt_assert(! c->have_sent_sufficiently_random_cell);
+ tt_int_op(c->send_randomness_after_n_cells, OP_GE,
+ CIRCWINDOW_INCREMENT / 2 - 1);
+
+ /* What would happen if we hadn't sent a sufficiently random cell? */
+ c->send_randomness_after_n_cells = 0;
+ n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c);
+ const size_t reduced_payload_size = RELAY_PAYLOAD_SIZE - 4 - 16;
+ tt_int_op(n, OP_EQ, reduced_payload_size);
+ /* Now these will be reset. */
+ tt_assert(! c->have_sent_sufficiently_random_cell);
+ tt_int_op(c->send_randomness_after_n_cells, OP_GE,
+ CIRCWINDOW_INCREMENT / 2 - 1);
+
+ /* Here is a fun case: if it's time to package a small cell, then
+ * package_partial==0 should mean we accept that many bytes.
+ */
+ c->send_randomness_after_n_cells = 0;
+ n = connection_edge_get_inbuf_bytes_to_package(reduced_payload_size, 0, c);
+ tt_int_op(n, OP_EQ, reduced_payload_size);
+
+ done:
+ tor_free(c);
+}
+
+struct testcase_t sendme_tests[] = {
+ { "v1_record_digest", test_v1_record_digest, TT_FORK,
+ NULL, NULL },
+ { "v1_consensus_params", test_v1_consensus_params, TT_FORK,
+ NULL, NULL },
+ { "v1_build_cell", test_v1_build_cell, TT_FORK,
+ NULL, NULL },
+ { "cell_payload_pad", test_cell_payload_pad, TT_FORK,
+ NULL, NULL },
+ { "cell_version_validation", test_cell_version_validation, TT_FORK,
+ NULL, NULL },
+ { "package_payload_len", test_package_payload_len, 0, NULL, NULL },
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c
index 413dfbeb03..678f53234f 100644
--- a/src/test/test_shared_random.c
+++ b/src/test/test_shared_random.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2019, The Tor Project, Inc. */
+/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define SHARED_RANDOM_PRIVATE
@@ -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"
@@ -58,14 +58,17 @@ trusteddirserver_get_by_v3_auth_digest_m(const char *digest)
}
/* Setup a minimal dirauth environment by initializing the SR state and
- * making sure the options are set to be an authority directory. */
+ * making sure the options are set to be an authority directory.
+ * You must only call this function once per process. */
static void
init_authority_state(void)
{
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
or_options_t *options = get_options_mutable();
- mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
+ mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1,
+ strlen(AUTHORITY_CERT_1),
+ NULL);
tt_assert(mock_cert);
options->AuthoritativeDir = 1;
tt_int_op(load_ed_keys(options, time(NULL)), OP_GE, 0);
@@ -201,7 +204,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
&current_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 */
@@ -213,7 +216,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 19:22:00 UTC",
&current_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);
@@ -224,7 +227,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:00 UTC",
&current_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);
@@ -235,7 +238,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
&current_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);
@@ -275,7 +278,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
&current_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 */
@@ -287,7 +290,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:59 UTC",
&current_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 */
@@ -299,7 +302,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
&current_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 */
@@ -323,12 +326,13 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 19 Apr 2015 23:00:00 UTC",
&mock_consensus.valid_after);
+ tt_int_op(retval, OP_EQ, 0);
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:08:00 UTC",
&current_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();
@@ -336,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);
}
@@ -356,7 +360,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:15:32 UTC",
&current_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 */
@@ -388,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:
@@ -438,7 +442,9 @@ test_sr_commit(void *arg)
{ /* Setup a minimal dirauth environment for this test */
or_options_t *options = get_options_mutable();
- auth_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
+ auth_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1,
+ strlen(AUTHORITY_CERT_1),
+ NULL);
tt_assert(auth_cert);
options->AuthoritativeDir = 1;
@@ -457,12 +463,12 @@ test_sr_commit(void *arg)
/* We should have a reveal value. */
tt_assert(commit_has_reveal_value(our_commit));
/* We should have a random value. */
- tt_assert(!tor_mem_is_zero((char *) our_commit->random_number,
+ tt_assert(!fast_mem_is_zero((char *) our_commit->random_number,
sizeof(our_commit->random_number)));
/* Commit and reveal timestamp should be the same. */
tt_u64_op(our_commit->commit_ts, OP_EQ, our_commit->reveal_ts);
/* We should have a hashed reveal. */
- tt_assert(!tor_mem_is_zero(our_commit->hashed_reveal,
+ tt_assert(!fast_mem_is_zero(our_commit->hashed_reveal,
sizeof(our_commit->hashed_reveal)));
/* Do we have a valid encoded commit and reveal. Note the following only
* tests if the generated values are correct. Their could be a bug in
@@ -849,7 +855,9 @@ test_sr_setup_commits(void)
{ /* Setup a minimal dirauth environment for this test */
or_options_t *options = get_options_mutable();
- auth_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
+ auth_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1,
+ strlen(AUTHORITY_CERT_1),
+ NULL);
tt_assert(auth_cert);
options->AuthoritativeDir = 1;
@@ -1087,73 +1095,99 @@ test_sr_get_majority_srv_from_votes(void *arg)
smartlist_free(votes);
}
+/* Testing sr_srv_dup(). */
static void
-test_utils(void *arg)
+test_sr_svr_dup(void *arg)
{
- (void) arg;
+ (void)arg;
- /* Testing srv_dup(). */
- {
- sr_srv_t *srv = NULL, *dup_srv = NULL;
- const char *srv_value =
- "1BDB7C3E973936E4D13A49F37C859B3DC69C429334CF9412E3FEF6399C52D47A";
- srv = tor_malloc_zero(sizeof(*srv));
- srv->num_reveals = 42;
- memcpy(srv->value, srv_value, sizeof(srv->value));
- dup_srv = srv_dup(srv);
- tt_assert(dup_srv);
- tt_u64_op(dup_srv->num_reveals, OP_EQ, srv->num_reveals);
- tt_mem_op(dup_srv->value, OP_EQ, srv->value, sizeof(srv->value));
- tor_free(srv);
- tor_free(dup_srv);
- }
+ sr_srv_t *srv = NULL, *dup_srv = NULL;
+ const char *srv_value =
+ "1BDB7C3E973936E4D13A49F37C859B3DC69C429334CF9412E3FEF6399C52D47A";
+ srv = tor_malloc_zero(sizeof(*srv));
+ srv->num_reveals = 42;
+ memcpy(srv->value, srv_value, sizeof(srv->value));
+ dup_srv = sr_srv_dup(srv);
+ tt_assert(dup_srv);
+ tt_u64_op(dup_srv->num_reveals, OP_EQ, srv->num_reveals);
+ tt_mem_op(dup_srv->value, OP_EQ, srv->value, sizeof(srv->value));
- /* Testing commitments_are_the_same(). Currently, the check is to test the
- * value of the encoded commit so let's make sure that actually works. */
- {
- /* Payload of 57 bytes that is the length of sr_commit_t->encoded_commit.
- * 56 bytes of payload and a NUL terminated byte at the end ('\x00')
- * which comes down to SR_COMMIT_BASE64_LEN + 1. */
- const char *payload =
- "\x5d\xb9\x60\xb6\xcc\x51\x68\x52\x31\xd9\x88\x88\x71\x71\xe0\x30"
- "\x59\x55\x7f\xcd\x61\xc0\x4b\x05\xb8\xcd\xc1\x48\xe9\xcd\x16\x1f"
- "\x70\x15\x0c\xfc\xd3\x1a\x75\xd0\x93\x6c\xc4\xe0\x5c\xbe\xe2\x18"
- "\xc7\xaf\x72\xb6\x7c\x9b\x52\x00";
- sr_commit_t commit1, commit2;
- memcpy(commit1.encoded_commit, payload, sizeof(commit1.encoded_commit));
- memcpy(commit2.encoded_commit, payload, sizeof(commit2.encoded_commit));
- tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 1);
- /* Let's corrupt one of them. */
- memset(commit1.encoded_commit, 'A', sizeof(commit1.encoded_commit));
- tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 0);
- }
+ done:
+ tor_free(srv);
+ tor_free(dup_srv);
+}
- /* Testing commit_is_authoritative(). */
- {
- crypto_pk_t *k = crypto_pk_new();
- char digest[DIGEST_LEN];
- sr_commit_t commit;
+/* Testing commitments_are_the_same(). Currently, the check is to test the
+ * value of the encoded commit so let's make sure that actually works. */
+static void
+test_commitments_are_the_same(void *arg)
+{
+ (void)arg;
+
+ /* Payload of 57 bytes that is the length of sr_commit_t->encoded_commit.
+ * 56 bytes of payload and a NUL terminated byte at the end ('\x00')
+ * which comes down to SR_COMMIT_BASE64_LEN + 1. */
+ const char *payload =
+ "\x5d\xb9\x60\xb6\xcc\x51\x68\x52\x31\xd9\x88\x88\x71\x71\xe0\x30"
+ "\x59\x55\x7f\xcd\x61\xc0\x4b\x05\xb8\xcd\xc1\x48\xe9\xcd\x16\x1f"
+ "\x70\x15\x0c\xfc\xd3\x1a\x75\xd0\x93\x6c\xc4\xe0\x5c\xbe\xe2\x18"
+ "\xc7\xaf\x72\xb6\x7c\x9b\x52\x00";
+ sr_commit_t commit1, commit2;
+ memcpy(commit1.encoded_commit, payload, sizeof(commit1.encoded_commit));
+ memcpy(commit2.encoded_commit, payload, sizeof(commit2.encoded_commit));
+ tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 1);
+ /* Let's corrupt one of them. */
+ memset(commit1.encoded_commit, 'A', sizeof(commit1.encoded_commit));
+ tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 0);
- tt_assert(!crypto_pk_generate_key(k));
+ done:
+ return;
+}
- tt_int_op(0, OP_EQ, crypto_pk_get_digest(k, digest));
- memcpy(commit.rsa_identity, digest, sizeof(commit.rsa_identity));
- tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 1);
- /* Change the pubkey. */
- memset(commit.rsa_identity, 0, sizeof(commit.rsa_identity));
- tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 0);
- crypto_pk_free(k);
- }
+/* Testing commit_is_authoritative(). */
+static void
+test_commit_is_authoritative(void *arg)
+{
+ (void)arg;
- /* Testing get_phase_str(). */
- {
- tt_str_op(get_phase_str(SR_PHASE_REVEAL), OP_EQ, "reveal");
- tt_str_op(get_phase_str(SR_PHASE_COMMIT), OP_EQ, "commit");
- }
+ crypto_pk_t *k = crypto_pk_new();
+ char digest[DIGEST_LEN];
+ sr_commit_t commit;
+
+ tt_assert(!crypto_pk_generate_key(k));
+
+ tt_int_op(0, OP_EQ, crypto_pk_get_digest(k, digest));
+ memcpy(commit.rsa_identity, digest, sizeof(commit.rsa_identity));
+ tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 1);
+ /* Change the pubkey. */
+ memset(commit.rsa_identity, 0, sizeof(commit.rsa_identity));
+ tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 0);
+
+ done:
+ crypto_pk_free(k);
+}
+
+static void
+test_get_phase_str(void *arg)
+{
+ (void)arg;
+
+ tt_str_op(get_phase_str(SR_PHASE_REVEAL), OP_EQ, "reveal");
+ tt_str_op(get_phase_str(SR_PHASE_COMMIT), OP_EQ, "commit");
+
+ done:
+ return;
+}
+
+/* Test utils that depend on authority state */
+static void
+test_utils_auth(void *arg)
+{
+ (void)arg;
+ init_authority_state();
/* Testing phase transition */
{
- init_authority_state();
set_sr_phase(SR_PHASE_COMMIT);
tt_int_op(is_phase_transition(SR_PHASE_REVEAL), OP_EQ, 1);
tt_int_op(is_phase_transition(SR_PHASE_COMMIT), OP_EQ, 0);
@@ -1164,8 +1198,193 @@ test_utils(void *arg)
tt_int_op(is_phase_transition(42), OP_EQ, 1);
}
+ /* Testing get, set, delete, clean SRVs */
+
+ {
+ /* Just set the previous SRV */
+ test_sr_setup_srv(0);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ state_del_previous_srv();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ }
+
+ {
+ /* Delete the SRVs one at a time */
+ test_sr_setup_srv(1);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ state_del_current_srv();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ state_del_previous_srv();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+
+ /* And in the opposite order */
+ test_sr_setup_srv(1);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ state_del_previous_srv();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ state_del_current_srv();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+
+ /* And both at once */
+ test_sr_setup_srv(1);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ sr_state_clean_srvs();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+
+ /* And do the gets and sets multiple times */
+ test_sr_setup_srv(1);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ state_del_previous_srv();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ state_del_previous_srv();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ sr_state_clean_srvs();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ state_del_current_srv();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ sr_state_clean_srvs();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ state_del_current_srv();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ }
+
+ {
+ /* Now set the SRVs to NULL instead */
+ test_sr_setup_srv(1);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ sr_state_set_current_srv(NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ sr_state_set_previous_srv(NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+
+ /* And in the opposite order */
+ test_sr_setup_srv(1);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ sr_state_set_previous_srv(NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ sr_state_set_current_srv(NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+
+ /* And both at once */
+ test_sr_setup_srv(1);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ sr_state_clean_srvs();
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+
+ /* And do the gets and sets multiple times */
+ test_sr_setup_srv(1);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ sr_state_set_previous_srv(NULL);
+ sr_state_set_previous_srv(NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ sr_state_set_current_srv(NULL);
+ sr_state_set_previous_srv(NULL);
+ sr_state_set_current_srv(NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ }
+
+ {
+ /* Now copy the values across */
+ test_sr_setup_srv(1);
+ /* Check that the pointers are non-NULL, and different from each other */
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE,
+ sr_state_get_current_srv());
+ /* Check that the content is different */
+ tt_mem_op(sr_state_get_previous_srv(), OP_NE,
+ sr_state_get_current_srv(), sizeof(sr_srv_t));
+ /* Set the current to the previous: the protocol goes the other way */
+ sr_state_set_current_srv(sr_srv_dup(sr_state_get_previous_srv()));
+ /* Check that the pointers are non-NULL, and different from each other */
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE,
+ sr_state_get_current_srv());
+ /* Check that the content is the same */
+ tt_mem_op(sr_state_get_previous_srv(), OP_EQ,
+ sr_state_get_current_srv(), sizeof(sr_srv_t));
+ }
+
+ {
+ /* Now copy a value onto itself */
+ test_sr_setup_srv(1);
+ /* Check that the pointers are non-NULL, and different from each other */
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE,
+ sr_state_get_current_srv());
+ /* Take a copy of the old value */
+ sr_srv_t old_current_srv;
+ memcpy(&old_current_srv, sr_state_get_current_srv(), sizeof(sr_srv_t));
+ /* Check that the content is different */
+ tt_mem_op(sr_state_get_previous_srv(), OP_NE,
+ sr_state_get_current_srv(), sizeof(sr_srv_t));
+ /* Set the current to the current: the protocol never replaces an SRV with
+ * the same value */
+ sr_state_set_current_srv(sr_srv_dup(sr_state_get_current_srv()));
+ /* Check that the pointers are non-NULL, and different from each other */
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_current_srv(), OP_NE, NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_NE,
+ sr_state_get_current_srv());
+ /* Check that the content is different between current and previous */
+ tt_mem_op(sr_state_get_previous_srv(), OP_NE,
+ sr_state_get_current_srv(), sizeof(sr_srv_t));
+ /* Check that the content is the same as the old content */
+ tt_mem_op(&old_current_srv, OP_EQ,
+ sr_state_get_current_srv(), sizeof(sr_srv_t));
+ }
+
+ /* I don't think we can say "expect a BUG()" in our tests. */
+#if 0
+ {
+ /* Now copy a value onto itself without sr_srv_dup().
+ * This should fail with a BUG() warning. */
+ test_sr_setup_srv(1);
+ sr_state_set_current_srv(sr_state_get_current_srv());
+ sr_state_set_previous_srv(sr_state_get_previous_srv());
+ }
+#endif /* 0 */
+
done:
- return;
+ sr_state_free_all();
}
static void
@@ -1173,6 +1392,7 @@ test_state_transition(void *arg)
{
sr_state_t *state = NULL;
time_t now = time(NULL);
+ sr_srv_t *cur = NULL;
(void) arg;
@@ -1194,7 +1414,7 @@ test_state_transition(void *arg)
sr_state_delete_commits();
tt_int_op(digestmap_size(state->commits), OP_EQ, 0);
/* Add it back so we can continue the rest of the test because after
- * deletiong our commit will be freed so generate a new one. */
+ * deleting our commit will be freed so generate a new one. */
commit = sr_generate_our_commit(now, mock_cert);
tt_assert(commit);
sr_state_add_commit(commit);
@@ -1211,44 +1431,47 @@ test_state_transition(void *arg)
/* Test SRV rotation in our state. */
{
- const sr_srv_t *cur, *prev;
test_sr_setup_srv(1);
- cur = sr_state_get_current_srv();
+ tt_assert(sr_state_get_current_srv());
+ /* Take a copy of the data, because the state owns the pointer */
+ cur = sr_srv_dup(sr_state_get_current_srv());
tt_assert(cur);
- /* After, current srv should be the previous and then set to NULL. */
+ /* After, the previous SRV should be the same as the old current SRV, and
+ * the current SRV should be set to NULL */
state_rotate_srv();
- prev = sr_state_get_previous_srv();
- tt_assert(prev == cur);
+ tt_mem_op(sr_state_get_previous_srv(), OP_EQ, cur, sizeof(sr_srv_t));
tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
sr_state_clean_srvs();
+ tor_free(cur);
}
/* New protocol run. */
{
- const sr_srv_t *cur;
/* Setup some new SRVs so we can confirm that a new protocol run
* actually makes them rotate and compute new ones. */
test_sr_setup_srv(1);
- cur = sr_state_get_current_srv();
- tt_assert(cur);
+ tt_assert(sr_state_get_current_srv());
+ /* Take a copy of the data, because the state owns the pointer */
+ cur = sr_srv_dup(sr_state_get_current_srv());
set_sr_phase(SR_PHASE_REVEAL);
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
new_protocol_run(now);
UNMOCK(get_my_v3_authority_cert);
/* Rotation happened. */
- tt_assert(sr_state_get_previous_srv() == cur);
+ tt_mem_op(sr_state_get_previous_srv(), OP_EQ, cur, sizeof(sr_srv_t));
/* We are going into COMMIT phase so we had to rotate our SRVs. Usually
* our current SRV would be NULL but a new protocol run should make us
* compute a new SRV. */
tt_assert(sr_state_get_current_srv());
/* Also, make sure we did change the current. */
- tt_assert(sr_state_get_current_srv() != cur);
+ tt_mem_op(sr_state_get_current_srv(), OP_NE, cur, sizeof(sr_srv_t));
/* We should have our commitment alone. */
tt_int_op(digestmap_size(state->commits), OP_EQ, 1);
tt_int_op(state->n_reveal_rounds, OP_EQ, 0);
tt_int_op(state->n_commit_rounds, OP_EQ, 0);
/* 46 here since we were at 45 just before. */
tt_u64_op(state->n_protocol_runs, OP_EQ, 46);
+ tor_free(cur);
}
/* Cleanup of SRVs. */
@@ -1259,6 +1482,7 @@ test_state_transition(void *arg)
}
done:
+ tor_free(cur);
sr_state_free_all();
}
@@ -1331,7 +1555,7 @@ test_keep_commit(void *arg)
* in the state and commitment and reveal values match. */
tt_int_op(should_keep_commit(commit, commit->rsa_identity,
SR_PHASE_REVEAL), OP_EQ, 1);
- /* The commit shouldn't be kept if it's not verified that is no matchin
+ /* The commit shouldn't be kept if it's not verified that is no matching
* hashed reveal. */
{
/* Let's save the hash reveal so we can restore it. */
@@ -1454,7 +1678,13 @@ struct testcase_t sr_tests[] = {
{ "sr_compute_srv", test_sr_compute_srv, TT_FORK, NULL, NULL },
{ "sr_get_majority_srv_from_votes", test_sr_get_majority_srv_from_votes,
TT_FORK, NULL, NULL },
- { "utils", test_utils, TT_FORK, NULL, NULL },
+ { "sr_svr_dup", test_sr_svr_dup, TT_FORK, NULL, NULL },
+ { "commitments_are_the_same", test_commitments_are_the_same, TT_FORK, NULL,
+ NULL },
+ { "commit_is_authoritative", test_commit_is_authoritative, TT_FORK, NULL,
+ NULL },
+ { "get_phase_str", test_get_phase_str, TT_FORK, NULL, NULL },
+ { "utils_auth", test_utils_auth, TT_FORK, NULL, NULL },
{ "state_transition", test_state_transition, TT_FORK, NULL, NULL },
{ "state_update", test_state_update, TT_FORK,
NULL, NULL },
diff --git a/src/test/test_slow.c b/src/test/test_slow.c
index bda67b2d92..49b1066dac 100644
--- a/src/test/test_slow.c
+++ b/src/test/test_slow.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,7 +20,9 @@
struct testgroup_t testgroups[] = {
{ "slow/crypto/", slow_crypto_tests },
- { "slow/util/", slow_util_tests },
+ { "slow/process/", slow_process_tests },
+ { "slow/prob_distr/", slow_stochastic_prob_distr_tests },
+ { "slow/ptr/", slow_ptr_tests },
END_OF_GROUPS
};
diff --git a/src/test/test_socks.c b/src/test/test_socks.c
index 3686e1036b..4a465c7361 100644
--- a/src/test/test_socks.c
+++ b/src/test/test_socks.c
@@ -1,10 +1,10 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "core/proto/proto_socks.h"
@@ -399,6 +399,43 @@ test_socks_5_supported_commands(void *ptr)
tt_int_op(0,OP_EQ, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send RESOLVE_PTR [F1] for an IPv6 address */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF1\x00\x04"
+ "\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34"
+ "\x12\x34");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, 1);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
+ tt_str_op("[2001:db8:85a3::8a2e:370:7334]",OP_EQ, socks->address);
+
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
+
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send RESOLVE_PTR [F1] for a an IPv6 address written as a
+ * string with brackets */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF1\x00\x03\x1e");
+ ADD_DATA(buf, "[2001:db8:85a3::8a2e:370:7334]");
+ ADD_DATA(buf, "\x12\x34");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, 1);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
+ tt_str_op("[2001:db8:85a3::8a2e:370:7334]",OP_EQ, socks->address);
+
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
+
done:
;
}
diff --git a/src/test/test_statefile.c b/src/test/test_statefile.c
new file mode 100644
index 0000000000..dc9ecfee3e
--- /dev/null
+++ b/src/test/test_statefile.c
@@ -0,0 +1,56 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define STATEFILE_PRIVATE
+
+#include "core/or/or.h"
+#include "lib/encoding/confline.h"
+#include "app/config/statefile.h"
+
+#include "test/test.h"
+
+static void
+test_statefile_remove_obsolete(void *arg)
+{
+ (void)arg;
+ config_line_t *inp = NULL;
+ /* try empty config */
+ or_state_remove_obsolete_lines(&inp);
+ tt_assert(!inp);
+
+ /* try removing every line */
+ config_line_append(&inp, "EntryGuard", "doesn't matter");
+ config_line_append(&inp, "HidServRevCounter", "ignore");
+ config_line_append(&inp, "hidservrevcounter", "foobar"); // note case
+ or_state_remove_obsolete_lines(&inp);
+ tt_assert(!inp);
+
+ /* Now try removing a subset of lines. */
+ config_line_append(&inp, "EntryGuard", "doesn't matter");
+ config_line_append(&inp, "Guard", "in use");
+ config_line_append(&inp, "HidServRevCounter", "ignore");
+ config_line_append(&inp, "TorVersion", "this test doesn't care");
+ or_state_remove_obsolete_lines(&inp);
+ tt_assert(inp);
+ tt_str_op(inp->key, OP_EQ, "Guard");
+ tt_str_op(inp->value, OP_EQ, "in use");
+ tt_assert(inp->next);
+ tt_str_op(inp->next->key, OP_EQ, "TorVersion");
+ tt_str_op(inp->next->value, OP_EQ, "this test doesn't care");
+ tt_assert(! inp->next->next);
+
+ done:
+ config_free_lines(inp);
+}
+
+#define T(name) \
+ { #name, test_statefile_##name, 0, NULL, NULL }
+
+struct testcase_t statefile_tests[] = {
+ T(remove_obsolete),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_stats.c b/src/test/test_stats.c
new file mode 100644
index 0000000000..d45afc7b15
--- /dev/null
+++ b/src/test/test_stats.c
@@ -0,0 +1,592 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_stats.c
+ * \brief Unit tests for the statistics (reputation history) module.
+ **/
+
+#include "orconfig.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "app/config/or_state_st.h"
+#include "test/rng_test_helpers.h"
+
+#include <stdio.h>
+
+#ifdef _WIN32
+/* For mkdir() */
+#include <direct.h>
+#else
+#include <dirent.h>
+#endif /* defined(_WIN32) */
+
+#include <math.h>
+
+/* These macros pull in declarations for some functions and structures that
+ * are typically file-private. */
+#define CIRCUITSTATS_PRIVATE
+#define CIRCUITLIST_PRIVATE
+#define MAINLOOP_PRIVATE
+#define STATEFILE_PRIVATE
+#define BWHIST_PRIVATE
+#define ROUTER_PRIVATE
+
+#include "core/or/or.h"
+#include "lib/err/backtrace.h"
+#include "lib/buf/buffers.h"
+#include "core/or/circuitstats.h"
+#include "app/config/config.h"
+#include "test/test.h"
+#include "core/mainloop/mainloop.h"
+#include "lib/memarea/memarea.h"
+#include "feature/stats/connstats.h"
+#include "feature/stats/rephist.h"
+#include "app/config/statefile.h"
+#include "feature/stats/bwhist.h"
+#include "feature/stats/bw_array_st.h"
+#include "feature/relay/router.h"
+
+/** Run unit tests for some stats code. */
+static void
+test_stats(void *arg)
+{
+ time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
+ char *s = NULL;
+ int i;
+
+ /* Start with testing exit port statistics; we shouldn't collect exit
+ * stats without initializing them. */
+ (void)arg;
+ rep_hist_note_exit_stream_opened(80);
+ rep_hist_note_exit_bytes(80, 100, 10000);
+ s = rep_hist_format_exit_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Initialize stats, note some streams and bytes, and generate history
+ * string. */
+ rep_hist_exit_stats_init(now);
+ rep_hist_note_exit_stream_opened(80);
+ rep_hist_note_exit_bytes(80, 100, 10000);
+ rep_hist_note_exit_stream_opened(443);
+ rep_hist_note_exit_bytes(443, 100, 10000);
+ rep_hist_note_exit_bytes(443, 100, 10000);
+ s = rep_hist_format_exit_stats(now + 86400);
+ tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "exit-kibibytes-written 80=1,443=1,other=0\n"
+ "exit-kibibytes-read 80=10,443=20,other=0\n"
+ "exit-streams-opened 80=4,443=4,other=0\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Add a few bytes on 10 more ports and ensure that only the top 10
+ * ports are contained in the history string. */
+ for (i = 50; i < 60; i++) {
+ rep_hist_note_exit_bytes(i, i, i);
+ rep_hist_note_exit_stream_opened(i);
+ }
+ s = rep_hist_format_exit_stats(now + 86400);
+ tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "exit-kibibytes-written 52=1,53=1,54=1,55=1,56=1,57=1,58=1,"
+ "59=1,80=1,443=1,other=1\n"
+ "exit-kibibytes-read 52=1,53=1,54=1,55=1,56=1,57=1,58=1,"
+ "59=1,80=10,443=20,other=1\n"
+ "exit-streams-opened 52=4,53=4,54=4,55=4,56=4,57=4,58=4,"
+ "59=4,80=4,443=4,other=4\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Stop collecting stats, add some bytes, and ensure we don't generate
+ * a history string. */
+ rep_hist_exit_stats_term();
+ rep_hist_note_exit_bytes(80, 100, 10000);
+ s = rep_hist_format_exit_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Re-start stats, add some bytes, reset stats, and see what history we
+ * get when observing no streams or bytes at all. */
+ rep_hist_exit_stats_init(now);
+ rep_hist_note_exit_stream_opened(80);
+ rep_hist_note_exit_bytes(80, 100, 10000);
+ rep_hist_reset_exit_stats(now);
+ s = rep_hist_format_exit_stats(now + 86400);
+ tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "exit-kibibytes-written other=0\n"
+ "exit-kibibytes-read other=0\n"
+ "exit-streams-opened other=0\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Continue with testing connection statistics; we shouldn't collect
+ * conn stats without initializing them. */
+ conn_stats_note_or_conn_bytes(1, 20, 400, now, false);
+ s = conn_stats_format(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Initialize stats, note bytes, and generate history string. */
+ conn_stats_init(now);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now, false);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now + 5, false);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 10, true);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 15, true);
+ s = conn_stats_format(now + 86400);
+ tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n"
+ "ipv6-conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",
+ OP_EQ, s);
+ tor_free(s);
+
+ /* Stop collecting stats, add some bytes, and ensure we don't generate
+ * a history string. */
+ conn_stats_terminate();
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 15, true);
+ s = conn_stats_format(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Re-start stats, add some bytes, reset stats, and see what history we
+ * get when observing no bytes at all. */
+ conn_stats_init(now);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now, false);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now + 5, false);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 10, true);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 15, true);
+ conn_stats_reset(now);
+ s = conn_stats_format(now + 86400);
+ tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n"
+ "ipv6-conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",
+ OP_EQ, s);
+ tor_free(s);
+
+ /* Continue with testing buffer statistics; we shouldn't collect buffer
+ * stats without initializing them. */
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Initialize stats, add statistics for a single circuit, and generate
+ * the history string. */
+ rep_hist_buffer_stats_init(now);
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "cell-processed-cells 20,0,0,0,0,0,0,0,0,0\n"
+ "cell-queued-cells 2.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
+ "0.00,0.00\n"
+ "cell-time-in-queue 2,0,0,0,0,0,0,0,0,0\n"
+ "cell-circuits-per-decile 1\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Add nineteen more circuit statistics to the one that's already in the
+ * history to see that the math works correctly. */
+ for (i = 21; i < 30; i++)
+ rep_hist_add_buffer_stats(2.0, 2.0, i);
+ for (i = 20; i < 30; i++)
+ rep_hist_add_buffer_stats(3.5, 3.5, i);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "cell-processed-cells 29,28,27,26,25,24,23,22,21,20\n"
+ "cell-queued-cells 2.75,2.75,2.75,2.75,2.75,2.75,2.75,2.75,"
+ "2.75,2.75\n"
+ "cell-time-in-queue 3,3,3,3,3,3,3,3,3,3\n"
+ "cell-circuits-per-decile 2\n",OP_EQ, s);
+ tor_free(s);
+
+ /* Stop collecting stats, add statistics for one circuit, and ensure we
+ * don't generate a history string. */
+ rep_hist_buffer_stats_term();
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ tt_ptr_op(s, OP_EQ, NULL);
+
+ /* Re-start stats, add statistics for one circuit, reset stats, and make
+ * sure that the history has all zeros. */
+ rep_hist_buffer_stats_init(now);
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ rep_hist_reset_buffer_stats(now);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "cell-processed-cells 0,0,0,0,0,0,0,0,0,0\n"
+ "cell-queued-cells 0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
+ "0.00,0.00\n"
+ "cell-time-in-queue 0,0,0,0,0,0,0,0,0,0\n"
+ "cell-circuits-per-decile 0\n",OP_EQ, s);
+
+ done:
+ tor_free(s);
+}
+
+/** Run unit tests the mtbf stats code. */
+static void
+test_rephist_mtbf(void *arg)
+{
+ (void)arg;
+
+ time_t now = 1572500000; /* 2010-10-31 05:33:20 UTC */
+ time_t far_future = MAX(now, time(NULL)) + 365*24*60*60;
+ int r;
+
+ /* Make a temporary datadir for these tests */
+ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_mtbf"));
+ tor_free(get_options_mutable()->DataDirectory);
+ get_options_mutable()->DataDirectory = tor_strdup(ddir_fname);
+ check_private_dir(ddir_fname, CPD_CREATE, NULL);
+
+ rep_history_clean(far_future);
+
+ /* No data */
+
+ r = rep_hist_load_mtbf_data(now);
+ tt_int_op(r, OP_EQ, -1);
+ rep_history_clean(far_future);
+
+ /* Blank data */
+
+ r = rep_hist_record_mtbf_data(now, 0);
+ tt_int_op(r, OP_EQ, 0);
+ r = rep_hist_load_mtbf_data(now);
+ tt_int_op(r, OP_EQ, 0);
+ rep_history_clean(far_future);
+
+ r = rep_hist_record_mtbf_data(now, 1);
+ tt_int_op(r, OP_EQ, 0);
+ r = rep_hist_load_mtbf_data(now);
+ tt_int_op(r, OP_EQ, 0);
+ rep_history_clean(far_future);
+
+ done:
+ rep_history_clean(far_future);
+ tor_free(ddir_fname);
+}
+
+static void
+test_commit_max(void *arg)
+{
+ (void) arg;
+ bw_array_t *b = bw_array_new();
+ time_t now = b->cur_obs_time;
+
+ commit_max(b);
+ tt_int_op(b->next_period, OP_EQ, now + 2*86400);
+
+ b->total_in_period = 100;
+ b->max_total = 10;
+ commit_max(b);
+ tor_assert(b->total_in_period == 0);
+ tor_assert(b->max_total == 0);
+ tt_int_op(b->totals[1], OP_EQ, 100);
+ tt_int_op(b->maxima[1], OP_EQ, 10);
+ tt_int_op(b->next_period, OP_EQ, now + 3*86400);
+
+ commit_max(b);
+ tt_int_op(b->next_period, OP_EQ, now + 4*86400);
+
+ commit_max(b);
+ tt_int_op(b->next_period, OP_EQ, now + 5*86400);
+
+ b->total_in_period = 100;
+ b->max_total = 10;
+ commit_max(b);
+ tor_assert(!b->next_max_idx);
+ tt_int_op(b->cur_obs_idx, OP_EQ, 0);
+ tt_int_op(b->totals[4], OP_EQ, 100);
+ tt_int_op(b->maxima[4], OP_EQ, 10);
+ tt_int_op(b->next_period, OP_EQ, now + 6*86400);
+ done:
+ bw_array_free(b);
+}
+
+#define test_obs(b, idx, time, tot, max) STMT_BEGIN \
+ tt_int_op(b->cur_obs_idx, OP_EQ, idx); \
+ tt_int_op(b->cur_obs_time, OP_EQ, time); \
+ tt_int_op(b->total_obs, OP_EQ, tot); \
+ tt_int_op(b->max_total, OP_EQ, max); \
+ STMT_END;
+
+static void
+test_advance_obs(void *arg)
+{
+ (void) arg;
+ int iter, tot = 0;
+ bw_array_t *b = bw_array_new();
+ time_t now = b->cur_obs_time;
+
+ for (iter = 0; iter < 10; ++iter) {
+ b->obs[b->cur_obs_idx] += 10;
+ tot += 10;
+ advance_obs(b);
+ if (iter == 9) {
+ /* The current value under cur_obs_idx was zeroed in last iterN. */
+ test_obs(b, 0, now+iter+1, tot - 10, tot);
+ break;
+ }
+ test_obs(b, iter+1, now+iter+1, tot, tot);
+ }
+
+ b->total_in_period = 100;
+ b->cur_obs_time = now + NUM_SECS_BW_SUM_INTERVAL - 1;
+ advance_obs(b);
+ test_obs(b, 1, now+NUM_SECS_BW_SUM_INTERVAL, 80, 0);
+ tt_int_op(b->maxima[0], OP_EQ, 100);
+ tt_int_op(b->totals[0], OP_EQ, 100);
+ tt_int_op(b->num_maxes_set, OP_EQ, 1);
+ done:
+ bw_array_free(b);
+}
+
+#define test_add_obs_(b, now, checknow, bw, tot) STMT_BEGIN \
+ tot += bw; \
+ add_obs(b, now, bw); \
+ tt_int_op(b->cur_obs_time, OP_EQ, checknow); \
+ tt_int_op(b->obs[b->cur_obs_idx], OP_EQ, bw); \
+ tt_int_op(b->total_in_period, OP_EQ, tot); \
+ STMT_END;
+
+static void
+test_add_obs(void *arg)
+{
+ (void) arg;
+ bw_array_t *b = bw_array_new();
+ time_t now = b->cur_obs_time;
+ uint64_t bw = 0, tot = 0;
+ /* Requests for the past should not be entertained. */
+ test_add_obs_(b, now-1, now, bw, tot);
+ /* Test the expected functionalities for random values. */
+ now += 53;
+ bw = 97;
+ test_add_obs_(b, now, now, bw, tot);
+
+ now += 60*60;
+ bw = 90;
+ test_add_obs_(b, now, now, bw, tot);
+
+ now += 24*60*60;
+ bw = 100;
+ tot = 0;
+ test_add_obs_(b, now, now, bw, tot);
+ done:
+ bw_array_free(b);
+}
+
+static or_options_t mock_options;
+
+static const or_options_t *
+mock_get_options(void)
+{
+ return &mock_options;
+}
+
+#define MAX_HIST_VALUE_LEN 21*NUM_TOTALS
+
+#define set_test_case(b, max, idx, a1, a2, a3, a4, a5) STMT_BEGIN \
+ b->num_maxes_set = max; \
+ b->next_max_idx = idx; \
+ b->totals[0] = a1; \
+ b->totals[1] = a2; \
+ b->totals[2] = a3; \
+ b->totals[3] = a4; \
+ b->totals[4] = a5; \
+ STMT_END;
+
+#define test_fill_bw(b, buf, rv, str, checkrv) STMT_BEGIN \
+ buf = tor_malloc_zero(MAX_HIST_VALUE_LEN); \
+ rv = bwhist_fill_bandwidth_history(buf, MAX_HIST_VALUE_LEN, b); \
+ tt_str_op(buf, OP_EQ, str); \
+ tt_int_op(rv, OP_EQ, checkrv); \
+ tor_free(buf); \
+ STMT_END;
+
+static void
+test_fill_bandwidth_history(void *arg)
+{
+ (void) arg;
+ bw_array_t *b = bw_array_new();
+ char *buf;
+ size_t rv;
+ /* Remember bandwidth is rounded down to the nearest 1K. */
+ /* Day 1. */
+ set_test_case(b, 0, 0, 0, 0, 0, 0, 0);
+ buf = tor_malloc_zero(MAX_HIST_VALUE_LEN);
+ rv = bwhist_fill_bandwidth_history(buf, MAX_HIST_VALUE_LEN, b);
+ tt_int_op(rv, OP_EQ, 0);
+ tor_free(buf);
+ /* Day 2. */
+ set_test_case(b, 1, 1, 1000, 0, 0, 0, 0);
+ test_fill_bw(b, buf, rv, "0", 1);
+ /* Day 3. */
+ set_test_case(b, 2, 2, 1000, 1500, 0, 0, 0);
+ test_fill_bw(b, buf, rv, "0,1024", 6);
+ /* Day 4. */
+ set_test_case(b, 3, 3, 1000, 1500, 3500, 0, 0);
+ test_fill_bw(b, buf, rv, "0,1024,3072", 11);
+ /* Day 5. */
+ set_test_case(b, 4, 4, 1000, 1500, 3500, 8000, 0);
+ test_fill_bw(b, buf, rv, "0,1024,3072,7168", 16);
+ /* Day 6. */
+ set_test_case(b, 5, 0, 1000, 1500, 3500, 8000, 6000);
+ test_fill_bw(b, buf, rv, "0,1024,3072,7168,5120", 21);
+ /* Day 7. */
+ /* Remember oldest entry first. */
+ set_test_case(b, 5, 1, 10000, 1500, 3500, 8000, 6000);
+ test_fill_bw(b, buf, rv, "1024,3072,7168,5120,9216", 24);
+ /* Mocking get_options to manipulate RelayBandwidthRate. */
+ MOCK(get_options, mock_get_options);
+ /* Limits bandwidth to 1 KBps. */
+ /* Cutoff is set to 88473600. */
+ mock_options.RelayBandwidthRate = 1024;
+ set_test_case(b, 5, 2, 88573600, 88473600, 10000, 8000, 6000);
+ test_fill_bw(b, buf, rv, "9216,7168,5120,88473600,88473600", 32);
+ done:
+ UNMOCK(get_options);
+ bw_array_free(b);
+}
+
+#define set_test_bw_lines(r, w, dr, dw, when) STMT_BEGIN \
+ bwhist_note_bytes_read(r, when, false); \
+ bwhist_note_bytes_written(w, when, false); \
+ bwhist_note_dir_bytes_read(dr, when); \
+ bwhist_note_dir_bytes_written(dw, when); \
+ STMT_END;
+
+#define test_get_bw_lines(str, checkstr) STMT_BEGIN \
+ str = bwhist_get_bandwidth_lines(); \
+ tt_str_op(str, OP_EQ, checkstr); \
+ tor_free(str); \
+ STMT_END;
+
+static void
+test_get_bandwidth_lines(void *arg)
+{
+ (void) arg;
+ char *str = NULL, *checkstr = NULL;
+ char t[ISO_TIME_LEN+1];
+ int len = (67+MAX_HIST_VALUE_LEN)*4;
+ checkstr = tor_malloc_zero(len);
+ time_t now = time(NULL);
+ bwhist_init();
+
+ /* Day 1. */
+ now += 86400;
+ set_test_bw_lines(5000, 5500, 3000, 3500, now - 6*60*60);
+ /* Day 2. */
+ now += 86400;
+ set_test_bw_lines(50000, 55000, 30000, 35000, now - 6*60*60);
+ /* Day 3. */
+ now += 86400;
+ set_test_bw_lines(25000, 27500, 15000, 17500, now - 6*60*60);
+ /* Day 4. */
+ now += 86400;
+ set_test_bw_lines(90000, 76000, 60000, 45000, now - 6*60*60);
+ /* Day 5. */
+ now += 86400;
+ set_test_bw_lines(500, 55000, 30000, 35000, now - 6*60*60);
+ set_test_bw_lines(0, 0, 0, 0, now);
+ format_iso_time(t, now);
+ tor_snprintf(checkstr, len, "write-history %s (86400 s) "
+ "5120,54272,26624,75776,54272\n"
+ "read-history %s (86400 s) "
+ "4096,49152,24576,89088,0\n"
+ "dirreq-write-history %s (86400 s) "
+ "3072,34816,17408,44032,34816\n"
+ "dirreq-read-history %s (86400 s) "
+ "2048,29696,14336,59392,29696\n",
+ t, t, t, t);
+ test_get_bw_lines(str, checkstr);
+
+ done:
+ tor_free(str);
+ tor_free(checkstr);
+ bwhist_free_all();
+}
+
+static void
+test_load_stats_file(void *arg)
+{
+ int ret;
+ char *content = NULL, *read_file_content = NULL, *fname = NULL;
+
+ (void) arg;
+
+ /* Load conn-stats. */
+ fname = get_datadir_fname("conn-stats");
+ tt_assert(fname);
+ read_file_content = tor_strdup(
+ "conn-bi-direct 2020-12-13 15:48:53 (86400 s) 12,34,56,78\n"
+ "ipv6-conn-bi-direct 2020-12-14 15:48:53 (86400 s) 21,43,65,87\n");
+ write_str_to_file(fname, read_file_content, 0);
+ ret = load_stats_file("conn-stats", "conn-bi-direct", 1607874000, &content);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(read_file_content, OP_EQ, content);
+
+ /* Load hidserv-stats. */
+ tor_free(fname);
+ fname = get_datadir_fname("hidserv-stats");
+ tt_assert(fname);
+ tor_free(read_file_content);
+ read_file_content = tor_strdup(
+ "hidserv-stats-end 2020-12-13 15:48:53 (86400 s)\n"
+ "hidserv-rend-relayed-cells 48754891 delta_f=2048 epsilon=0.30 "
+ "bin_size=1024\n"
+ "hidserv-dir-onions-seen 53 delta_f=8 epsilon=0.30 bin_size=8\n");
+ write_str_to_file(fname, read_file_content, 0);
+ tor_free(content);
+ ret = load_stats_file("hidserv-stats", "hidserv-stats-end", 1607874000,
+ &content);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(read_file_content, OP_EQ, content);
+
+ /* Load dirreq-stats. */
+ tor_free(fname);
+ fname = get_datadir_fname("dirreq-stats");
+ tt_assert(fname);
+ tor_free(read_file_content);
+ read_file_content = tor_strdup(
+ "dirreq-stats-end 2020-12-13 15:48:53 (86400 s)\n"
+ "dirreq-v3-ips ru=1728,us=1144,de=696,ir=432,gb=328,fr=304,in=296,ua=232\n"
+ "dirreq-v3-reqs ru=3616,us=3576,de=1896,fr=800,gb=632,ir=616\n"
+ "dirreq-v3-resp ok=18472,not-enough-sigs=0,unavailable=0,not-found=0,"
+ "not-modified=3136,busy=0\n"
+ "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v3-tunneled-dl complete=18124,timeout=348,running=4,min=257,"
+ "d1=133653,d2=221050,q1=261242,d3=300622,d4=399758,md=539051,d6=721322,"
+ "d7=959866,q3=1103363,d8=1302035,d9=2046125,max=113404000\n");
+ write_str_to_file(fname, read_file_content, 0);
+ tor_free(content);
+ ret = load_stats_file("dirreq-stats", "dirreq-stats-end", 1607874000,
+ &content);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(read_file_content, OP_EQ, content);
+
+ /* Attempt to load future-stats file not starting with timestamp tag. */
+ tor_free(fname);
+ fname = get_datadir_fname("future-stats");
+ tt_assert(fname);
+ tor_free(read_file_content);
+ read_file_content = tor_strdup(
+ "future-stuff-at-file-start\n"
+ "future-stats 2020-12-13 15:48:53 (86400 s)\n");
+ write_str_to_file(fname, read_file_content, 0);
+ tor_free(content);
+ ret = load_stats_file("future-stats", "future-stats", 1607874000, &content);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(read_file_content, OP_EQ, content);
+
+ done:
+ tor_free(fname);
+ tor_free(read_file_content);
+ tor_free(content);
+}
+
+#define ENT(name) \
+ { #name, test_ ## name , 0, NULL, NULL }
+#define FORK(name) \
+ { #name, test_ ## name , TT_FORK, NULL, NULL }
+
+struct testcase_t stats_tests[] = {
+ FORK(stats),
+ ENT(rephist_mtbf),
+ FORK(commit_max),
+ FORK(advance_obs),
+ FORK(add_obs),
+ FORK(fill_bandwidth_history),
+ FORK(get_bandwidth_lines),
+ FORK(load_stats_file),
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_status.c b/src/test/test_status.c
index 9c47469975..b938b86326 100644
--- a/src/test/test_status.c
+++ b/src/test/test_status.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define STATUS_PRIVATE
@@ -26,6 +26,7 @@
#include "feature/nodelist/nodelist.h"
#include "app/config/statefile.h"
#include "lib/tls/tortls.h"
+#include "test/log_test_helpers.h"
#include "core/or/origin_circuit_st.h"
#include "app/config/or_state_st.h"
@@ -33,10 +34,6 @@
#include "test/test.h"
-#define NS_MODULE status
-
-#define NS_SUBMODULE count_circuits
-
/*
* Test that count_circuits() is correctly counting the number of
* global circuits.
@@ -44,10 +41,10 @@
static smartlist_t * mock_global_circuitlist = NULL;
-NS_DECL(smartlist_t *, circuit_get_global_list, (void));
+static smartlist_t * status_count_circuits_circuit_get_global_list(void);
static void
-NS(test_main)(void *arg)
+test_status_count_circuits(void *arg)
{
/* Choose origin_circuit_t wlog. */
origin_circuit_t *mock_circuit1, *mock_circuit2;
@@ -61,7 +58,8 @@ NS(test_main)(void *arg)
smartlist_add(mock_global_circuitlist, TO_CIRCUIT(mock_circuit1));
smartlist_add(mock_global_circuitlist, TO_CIRCUIT(mock_circuit2));
- NS_MOCK(circuit_get_global_list);
+ MOCK(circuit_get_global_list,
+ status_count_circuits_circuit_get_global_list);
actual_circuits = count_circuits();
@@ -72,25 +70,22 @@ NS(test_main)(void *arg)
tor_free(mock_circuit2);
smartlist_free(mock_global_circuitlist);
mock_global_circuitlist = NULL;
- NS_UNMOCK(circuit_get_global_list);
+ UNMOCK(circuit_get_global_list);
}
static smartlist_t *
-NS(circuit_get_global_list)(void)
+status_count_circuits_circuit_get_global_list(void)
{
return mock_global_circuitlist;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE secs_to_uptime
-
/*
* Test that secs_to_uptime() is converting the number of seconds that
* Tor is up for into the appropriate string form containing hours and minutes.
*/
static void
-NS(test_main)(void *arg)
+test_status_secs_to_uptime(void *arg)
{
const char *expected;
char *actual;
@@ -161,9 +156,6 @@ NS(test_main)(void *arg)
tor_free(actual);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE bytes_to_usage
-
/*
* Test that bytes_to_usage() is correctly converting the number of bytes that
* Tor has read/written into the appropriate string form containing kilobytes,
@@ -171,7 +163,7 @@ NS(test_main)(void *arg)
*/
static void
-NS(test_main)(void *arg)
+test_status_bytes_to_usage(void *arg)
{
const char *expected;
char *actual;
@@ -242,29 +234,30 @@ NS(test_main)(void *arg)
tor_free(actual);
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, fails)
-
/*
* Tests that log_heartbeat() fails when in the public server mode,
* not hibernating, and we couldn't get the current routerinfo.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+static double status_hb_fails_tls_get_write_overhead_ratio(void);
+static int status_hb_fails_we_are_hibernating(void);
+static int status_hb_fails_public_server_mode(const or_options_t *options);
+static const routerinfo_t * status_hb_fails_router_get_my_routerinfo(void);
static void
-NS(test_main)(void *arg)
+test_status_hb_fails(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(router_get_my_routerinfo);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_fails_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_fails_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_fails_public_server_mode);
+ MOCK(router_get_my_routerinfo,
+ status_hb_fails_router_get_my_routerinfo);
expected = -1;
actual = log_heartbeat(0);
@@ -272,26 +265,26 @@ NS(test_main)(void *arg)
tt_int_op(actual, OP_EQ, expected);
done:
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(router_get_my_routerinfo);
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(router_get_my_routerinfo);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_fails_tls_get_write_overhead_ratio(void)
{
return 2.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_fails_we_are_hibernating(void)
{
return 0;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_fails_public_server_mode(const or_options_t *options)
{
(void)options;
@@ -299,43 +292,45 @@ NS(public_server_mode)(const or_options_t *options)
}
static const routerinfo_t *
-NS(router_get_my_routerinfo)(void)
+status_hb_fails_router_get_my_routerinfo(void)
{
return NULL;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, not_in_consensus)
-
/*
* Tests that log_heartbeat() logs appropriately if we are not in the cached
* consensus.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
-NS_DECL(const node_t *, node_get_by_id, (const char *identity_digest));
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap));
-NS_DECL(int, server_mode, (const or_options_t *options));
+static double status_hb_not_in_consensus_tls_get_write_overhead_ratio(void);
+static int status_hb_not_in_consensus_we_are_hibernating(void);
+static int status_hb_not_in_consensus_public_server_mode(
+ const or_options_t *options);
+static const routerinfo_t *status_hb_not_in_consensus_get_my_routerinfo(void);
+static const node_t * status_hb_not_in_consensus_node_get_by_id(
+ const char *identity_digest);
+static int status_hb_not_in_consensus_server_mode(const or_options_t *options);
static routerinfo_t *mock_routerinfo;
static void
-NS(test_main)(void *arg)
+test_status_hb_not_in_consensus(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(router_get_my_routerinfo);
- NS_MOCK(node_get_by_id);
- NS_MOCK(logv);
- NS_MOCK(server_mode);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_not_in_consensus_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_not_in_consensus_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_not_in_consensus_public_server_mode);
+ MOCK(router_get_my_routerinfo,
+ status_hb_not_in_consensus_get_my_routerinfo);
+ MOCK(node_get_by_id,
+ status_hb_not_in_consensus_node_get_by_id);
+ MOCK(server_mode,
+ status_hb_not_in_consensus_server_mode);
log_global_min_severity_ = LOG_DEBUG;
onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP] = 1;
@@ -344,36 +339,56 @@ NS(test_main)(void *arg)
onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR] = 1;
expected = 0;
+ setup_capture_of_logs(LOG_INFO);
actual = log_heartbeat(0);
-
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(CALLED(logv), OP_EQ, 6);
- done:
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(router_get_my_routerinfo);
- NS_UNMOCK(node_get_by_id);
- NS_UNMOCK(logv);
- NS_UNMOCK(server_mode);
+ expect_log_msg("Heartbeat: It seems like we are "
+ "not in the cached consensus.\n");
+ expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, "
+ "with 0 circuits open. "
+ "I've sent 0 kB and received 0 kB. "
+ "I've received 0 connections on IPv4 and 0 on IPv6. "
+ "I've made 0 connections with IPv4 and 0 with IPv6.\n");
+ expect_log_msg("Average packaged cell fullness: 100.000%. "
+ "TLS write overhead: 0%\n");
+ expect_log_msg("Circuit handshake stats since last time: 1/1 TAP, "
+ "1/1 NTor.\n");
+ expect_log_msg("Since startup we initiated 0 and received 0 v1 "
+ "connections; initiated 0 and received 0 v2 connections; "
+ "initiated 0 and received 0 v3 connections; "
+ "initiated 0 and received 0 v4 connections; "
+ "initiated 0 and received 0 v5 connections.\n");
+ expect_log_msg("DoS mitigation since startup: 0 circuits killed with "
+ "too many cells. [cc not enabled] [conn not enabled] "
+ "0 INTRODUCE2 rejected.\n");
+ tt_int_op(mock_saved_log_n_entries(), OP_EQ, 6);
+
+ done:
+ teardown_capture_of_logs();
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(router_get_my_routerinfo);
+ UNMOCK(node_get_by_id);
+ UNMOCK(server_mode);
tor_free(mock_routerinfo);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_not_in_consensus_tls_get_write_overhead_ratio(void)
{
return 1.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_not_in_consensus_we_are_hibernating(void)
{
return 0;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_not_in_consensus_public_server_mode(const or_options_t *options)
{
(void)options;
@@ -381,7 +396,7 @@ NS(public_server_mode)(const or_options_t *options)
}
static const routerinfo_t *
-NS(router_get_my_routerinfo)(void)
+status_hb_not_in_consensus_get_my_routerinfo(void)
{
mock_routerinfo = tor_malloc(sizeof(routerinfo_t));
@@ -389,158 +404,95 @@ NS(router_get_my_routerinfo)(void)
}
static const node_t *
-NS(node_get_by_id)(const char *identity_digest)
+status_hb_not_in_consensus_node_get_by_id(const char *identity_digest)
{
(void)identity_digest;
return NULL;
}
-static void
-NS(logv)(int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap)
-{
- switch (CALLED(logv))
- {
- case 0:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: It seems like we are not in the cached consensus.");
- break;
- case 1:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Tor's uptime is %s, with %d circuits open. "
- "I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
- break;
- case 2:
- tt_int_op(severity, OP_EQ, LOG_INFO);
- break;
- case 3:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "rep_hist_log_circuit_handshake_stats"),
- OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Circuit handshake stats since last time: %d/%d TAP, %d/%d NTor.");
- tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes assigned (TAP) */
- tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes requested (TAP) */
- tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes assigned (NTOR) */
- tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes requested (NTOR) */
- break;
- case 4:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "rep_hist_log_link_protocol_counts"),
- OP_NE, NULL);
- break;
- case 5:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_str_op(format, OP_EQ, "DoS mitigation since startup:%s%s%s%s");
- tt_str_op(va_arg(ap, char *), OP_EQ,
- " 0 circuits killed with too many cells.");
- tt_str_op(va_arg(ap, char *), OP_EQ, " [cc not enabled]");
- tt_str_op(va_arg(ap, char *), OP_EQ, " [conn not enabled]");
- tt_str_op(va_arg(ap, char *), OP_EQ, "");
- break;
- default:
- tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
- break;
- }
-
- done:
- CALLED(logv)++;
-}
-
static int
-NS(server_mode)(const or_options_t *options)
+status_hb_not_in_consensus_server_mode(const or_options_t *options)
{
(void)options;
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, simple)
-
/*
* Tests that log_heartbeat() correctly logs heartbeat information
* normally.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(long, get_uptime, (void));
-NS_DECL(uint64_t, get_bytes_read, (void));
-NS_DECL(uint64_t, get_bytes_written, (void));
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap));
-NS_DECL(int, server_mode, (const or_options_t *options));
-
-static int NS(n_msgs) = 0;
+static double status_hb_simple_tls_get_write_overhead_ratio(void);
+static int status_hb_simple_we_are_hibernating(void);
+static int status_hb_simple_public_server_mode(const or_options_t *options);
+static long status_hb_simple_get_uptime(void);
+static uint64_t status_hb_simple_get_bytes_read(void);
+static uint64_t status_hb_simple_get_bytes_written(void);
+static int status_hb_simple_server_mode(const or_options_t *options);
static void
-NS(test_main)(void *arg)
+test_status_hb_simple(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(get_uptime);
- NS_MOCK(get_bytes_read);
- NS_MOCK(get_bytes_written);
- NS_MOCK(logv);
- NS_MOCK(server_mode);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_simple_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_simple_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_simple_public_server_mode);
+ MOCK(get_uptime,
+ status_hb_simple_get_uptime);
+ MOCK(get_bytes_read,
+ status_hb_simple_get_bytes_read);
+ MOCK(get_bytes_written,
+ status_hb_simple_get_bytes_written);
+ MOCK(server_mode,
+ status_hb_simple_server_mode);
log_global_min_severity_ = LOG_DEBUG;
+ setup_capture_of_logs(LOG_INFO);
expected = 0;
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(NS(n_msgs), OP_EQ, 1);
+
+ expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, "
+ "with 0 circuits open. "
+ "I've sent 0 kB and received 0 kB. "
+ "I've received 0 connections on IPv4 and 0 on IPv6. "
+ "I've made 0 connections with IPv4 and 0 with IPv6. "
+ "We are currently hibernating.\n");
done:
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(get_uptime);
- NS_UNMOCK(get_bytes_read);
- NS_UNMOCK(get_bytes_written);
- NS_UNMOCK(logv);
- NS_UNMOCK(server_mode);
+ teardown_capture_of_logs();
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(get_uptime);
+ UNMOCK(get_bytes_read);
+ UNMOCK(get_bytes_written);
+ UNMOCK(server_mode);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_simple_tls_get_write_overhead_ratio(void)
{
return 1.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_simple_we_are_hibernating(void)
{
return 1;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_simple_public_server_mode(const or_options_t *options)
{
(void)options;
@@ -548,135 +500,129 @@ NS(public_server_mode)(const or_options_t *options)
}
static long
-NS(get_uptime)(void)
+status_hb_simple_get_uptime(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_read)(void)
+status_hb_simple_get_bytes_read(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_written)(void)
+status_hb_simple_get_bytes_written(void)
{
return 0;
}
-static void
-NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
- const char *suffix, const char *format, va_list ap)
-{
- if (severity == LOG_INFO)
- return;
- ++NS(n_msgs);
-
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Tor's uptime is %s, with %d circuits open. "
- "I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, " We are currently hibernating.");
-
- done:
- ;
-}
-
static int
-NS(server_mode)(const or_options_t *options)
+status_hb_simple_server_mode(const or_options_t *options)
{
(void)options;
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, calls_log_accounting)
-
/*
* Tests that log_heartbeat() correctly logs heartbeat information
* and accounting information when configured.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(long, get_uptime, (void));
-NS_DECL(uint64_t, get_bytes_read, (void));
-NS_DECL(uint64_t, get_bytes_written, (void));
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap));
-NS_DECL(int, server_mode, (const or_options_t *options));
-NS_DECL(or_state_t *, get_or_state, (void));
-NS_DECL(int, accounting_is_enabled, (const or_options_t *options));
-NS_DECL(time_t, accounting_get_end_time, (void));
-
-static or_state_t * NS(mock_state) = NULL;
-static or_options_t * NS(mock_options) = NULL;
+static double status_hb_calls_log_accounting_tls_get_write_overhead_ratio(
+ void);
+static int status_hb_calls_log_accounting_we_are_hibernating(void);
+static int status_hb_calls_log_accounting_public_server_mode(
+ const or_options_t *options);
+static long status_hb_calls_log_accounting_get_uptime(void);
+static uint64_t status_hb_calls_log_accounting_get_bytes_read(void);
+static uint64_t status_hb_calls_log_accounting_get_bytes_written(void);
+static int status_hb_calls_log_accounting_server_mode(
+ const or_options_t *options);
+static or_state_t * status_hb_calls_log_accounting_get_or_state(void);
+static int status_hb_calls_log_accounting_accounting_is_enabled(
+ const or_options_t *options);
+static time_t status_hb_calls_log_accounting_accounting_get_end_time(void);
+
+static or_state_t * status_hb_calls_log_accounting_mock_state = NULL;
+static or_options_t * status_hb_calls_log_accounting_mock_options = NULL;
static void
-NS(test_main)(void *arg)
+test_status_hb_calls_log_accounting(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(get_uptime);
- NS_MOCK(get_bytes_read);
- NS_MOCK(get_bytes_written);
- NS_MOCK(logv);
- NS_MOCK(server_mode);
- NS_MOCK(get_or_state);
- NS_MOCK(accounting_is_enabled);
- NS_MOCK(accounting_get_end_time);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_calls_log_accounting_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_calls_log_accounting_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_calls_log_accounting_public_server_mode);
+ MOCK(get_uptime,
+ status_hb_calls_log_accounting_get_uptime);
+ MOCK(get_bytes_read,
+ status_hb_calls_log_accounting_get_bytes_read);
+ MOCK(get_bytes_written,
+ status_hb_calls_log_accounting_get_bytes_written);
+ MOCK(server_mode,
+ status_hb_calls_log_accounting_server_mode);
+ MOCK(get_or_state,
+ status_hb_calls_log_accounting_get_or_state);
+ MOCK(accounting_is_enabled,
+ status_hb_calls_log_accounting_accounting_is_enabled);
+ MOCK(accounting_get_end_time,
+ status_hb_calls_log_accounting_accounting_get_end_time);
log_global_min_severity_ = LOG_DEBUG;
+ setup_capture_of_logs(LOG_NOTICE);
expected = 0;
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(CALLED(logv), OP_EQ, 3);
+
+ expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, "
+ "with 0 circuits open. "
+ "I've sent 0 kB and received 0 kB. "
+ "I've received 0 connections on IPv4 and 0 on IPv6. "
+ "I've made 0 connections with IPv4 and 0 with IPv6.\n");
+
+ expect_log_msg_containing("Heartbeat: Accounting enabled. Sent: 0 kB, "
+ "Received: 0 kB, Used: 0 kB / 0 kB, Rule: max. "
+ "The current accounting interval ends on ");
+ tt_int_op(mock_saved_log_n_entries(), OP_EQ, 2);
done:
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(get_uptime);
- NS_UNMOCK(get_bytes_read);
- NS_UNMOCK(get_bytes_written);
- NS_UNMOCK(logv);
- NS_UNMOCK(server_mode);
- NS_UNMOCK(accounting_is_enabled);
- NS_UNMOCK(accounting_get_end_time);
- tor_free_(NS(mock_state));
- tor_free_(NS(mock_options));
+ teardown_capture_of_logs();
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(get_uptime);
+ UNMOCK(get_bytes_read);
+ UNMOCK(get_bytes_written);
+ UNMOCK(server_mode);
+ UNMOCK(accounting_is_enabled);
+ UNMOCK(accounting_get_end_time);
+ tor_free_(status_hb_calls_log_accounting_mock_state);
+ tor_free_(status_hb_calls_log_accounting_mock_options);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_calls_log_accounting_tls_get_write_overhead_ratio(void)
{
return 1.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_calls_log_accounting_we_are_hibernating(void)
{
return 0;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_calls_log_accounting_public_server_mode(const or_options_t *options)
{
(void)options;
@@ -684,77 +630,25 @@ NS(public_server_mode)(const or_options_t *options)
}
static long
-NS(get_uptime)(void)
+status_hb_calls_log_accounting_get_uptime(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_read)(void)
+status_hb_calls_log_accounting_get_bytes_read(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_written)(void)
+status_hb_calls_log_accounting_get_bytes_written(void)
{
return 0;
}
-static void
-NS(logv)(int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap)
-{
- switch (CALLED(logv))
- {
- case 0:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Tor's uptime is %s, with %d circuits open. "
- "I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
- break;
- case 1:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_accounting"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Accounting enabled. Sent: %s, Received: %s, Used: %s / "
- "%s, Rule: %s. The current accounting interval ends on %s, in %s.");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_used */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_max */
- tt_str_op(va_arg(ap, char *), OP_EQ, "max"); /* acc_rule */
- /* format_local_iso_time uses local tz, so we can't just compare
- * the string against a constant */
- char datetime[ISO_TIME_LEN+1];
- format_local_iso_time(datetime, 60);
- tt_str_op(va_arg(ap, char *), OP_EQ, datetime); /* end_buf */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:01 hours"); /* remaining */
- break;
- case 2:
- tt_int_op(severity, OP_EQ, LOG_INFO);
- break;
- default:
- tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
- break;
- }
-
- done:
- CALLED(logv)++;
-}
-
static int
-NS(server_mode)(const or_options_t *options)
+status_hb_calls_log_accounting_server_mode(const or_options_t *options)
{
(void)options;
@@ -762,7 +656,8 @@ NS(server_mode)(const or_options_t *options)
}
static int
-NS(accounting_is_enabled)(const or_options_t *options)
+status_hb_calls_log_accounting_accounting_is_enabled(
+ const or_options_t *options)
{
(void)options;
@@ -770,93 +665,110 @@ NS(accounting_is_enabled)(const or_options_t *options)
}
static time_t
-NS(accounting_get_end_time)(void)
+status_hb_calls_log_accounting_accounting_get_end_time(void)
{
return 60;
}
static or_state_t *
-NS(get_or_state)(void)
+status_hb_calls_log_accounting_get_or_state(void)
{
- NS(mock_state) = tor_malloc_zero(sizeof(or_state_t));
- NS(mock_state)->AccountingBytesReadInInterval = 0;
- NS(mock_state)->AccountingBytesWrittenInInterval = 0;
+ status_hb_calls_log_accounting_mock_state =
+ tor_malloc_zero(sizeof(or_state_t));
+ status_hb_calls_log_accounting_mock_state
+ ->AccountingBytesReadInInterval = 0;
+ status_hb_calls_log_accounting_mock_state
+ ->AccountingBytesWrittenInInterval = 0;
- return NS(mock_state);
+ return status_hb_calls_log_accounting_mock_state;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, packaged_cell_fullness)
-
/*
* Tests that log_heartbeat() correctly logs packaged cell
* fullness information.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(long, get_uptime, (void));
-NS_DECL(uint64_t, get_bytes_read, (void));
-NS_DECL(uint64_t, get_bytes_written, (void));
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap));
-NS_DECL(int, server_mode, (const or_options_t *options));
-NS_DECL(int, accounting_is_enabled, (const or_options_t *options));
+static double status_hb_packaged_cell_fullness_tls_get_write_overhead_ratio(
+ void);
+static int status_hb_packaged_cell_fullness_we_are_hibernating(void);
+static int status_hb_packaged_cell_fullness_public_server_mode(
+ const or_options_t *options);
+static long status_hb_packaged_cell_fullness_get_uptime(void);
+static uint64_t status_hb_packaged_cell_fullness_get_bytes_read(void);
+static uint64_t status_hb_packaged_cell_fullness_get_bytes_written(void);
+static int status_hb_packaged_cell_fullness_server_mode(
+ const or_options_t *options);
+static int status_hb_packaged_cell_fullness_accounting_is_enabled(
+ const or_options_t *options);
static void
-NS(test_main)(void *arg)
+test_status_hb_packaged_cell_fullness(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(get_uptime);
- NS_MOCK(get_bytes_read);
- NS_MOCK(get_bytes_written);
- NS_MOCK(logv);
- NS_MOCK(server_mode);
- NS_MOCK(accounting_is_enabled);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_packaged_cell_fullness_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_packaged_cell_fullness_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_packaged_cell_fullness_public_server_mode);
+ MOCK(get_uptime,
+ status_hb_packaged_cell_fullness_get_uptime);
+ MOCK(get_bytes_read,
+ status_hb_packaged_cell_fullness_get_bytes_read);
+ MOCK(get_bytes_written,
+ status_hb_packaged_cell_fullness_get_bytes_written);
+ MOCK(server_mode,
+ status_hb_packaged_cell_fullness_server_mode);
+ MOCK(accounting_is_enabled,
+ status_hb_packaged_cell_fullness_accounting_is_enabled);
log_global_min_severity_ = LOG_DEBUG;
stats_n_data_bytes_packaged = RELAY_PAYLOAD_SIZE;
stats_n_data_cells_packaged = 2;
expected = 0;
+ setup_capture_of_logs(LOG_INFO);
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(CALLED(logv), OP_EQ, 2);
+ expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, "
+ "with 0 circuits open. "
+ "I've sent 0 kB and received 0 kB. "
+ "I've received 0 connections on IPv4 and 0 on IPv6. "
+ "I've made 0 connections with IPv4 and 0 with IPv6.\n");
+ expect_log_msg("Average packaged cell fullness: 50.000%. "
+ "TLS write overhead: 0%\n");
done:
+ teardown_capture_of_logs();
stats_n_data_bytes_packaged = 0;
stats_n_data_cells_packaged = 0;
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(get_uptime);
- NS_UNMOCK(get_bytes_read);
- NS_UNMOCK(get_bytes_written);
- NS_UNMOCK(logv);
- NS_UNMOCK(server_mode);
- NS_UNMOCK(accounting_is_enabled);
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(get_uptime);
+ UNMOCK(get_bytes_read);
+ UNMOCK(get_bytes_written);
+ UNMOCK(server_mode);
+ UNMOCK(accounting_is_enabled);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_packaged_cell_fullness_tls_get_write_overhead_ratio(void)
{
return 1.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_packaged_cell_fullness_we_are_hibernating(void)
{
return 0;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_packaged_cell_fullness_public_server_mode(
+ const or_options_t *options)
{
(void)options;
@@ -864,65 +776,25 @@ NS(public_server_mode)(const or_options_t *options)
}
static long
-NS(get_uptime)(void)
+status_hb_packaged_cell_fullness_get_uptime(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_read)(void)
+status_hb_packaged_cell_fullness_get_bytes_read(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_written)(void)
+status_hb_packaged_cell_fullness_get_bytes_written(void)
{
return 0;
}
-static void
-NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
- const char *suffix, const char *format, va_list ap)
-{
- switch (CALLED(logv))
- {
- case 0:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Tor's uptime is %s, with %d circuits open. "
- "I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
- break;
- case 1:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Average packaged cell fullness: %2.3f%%. "
- "TLS write overhead: %.f%%");
- tt_double_op(fabs(va_arg(ap, double) - 50.0), OP_LE, DBL_EPSILON);
- tt_double_op(fabs(va_arg(ap, double) - 0.0), OP_LE, DBL_EPSILON);
- break;
- default:
- tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
- break;
- }
-
- done:
- CALLED(logv)++;
-}
-
static int
-NS(server_mode)(const or_options_t *options)
+status_hb_packaged_cell_fullness_server_mode(const or_options_t *options)
{
(void)options;
@@ -930,82 +802,95 @@ NS(server_mode)(const or_options_t *options)
}
static int
-NS(accounting_is_enabled)(const or_options_t *options)
+status_hb_packaged_cell_fullness_accounting_is_enabled(
+ const or_options_t *options)
{
(void)options;
return 0;
}
-#undef NS_SUBMODULE
-#define NS_SUBMODULE ASPECT(log_heartbeat, tls_write_overhead)
-
/*
* Tests that log_heartbeat() correctly logs the TLS write overhead information
* when the TLS write overhead ratio exceeds 1.
*/
-NS_DECL(double, tls_get_write_overhead_ratio, (void));
-NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(int, public_server_mode, (const or_options_t *options));
-NS_DECL(long, get_uptime, (void));
-NS_DECL(uint64_t, get_bytes_read, (void));
-NS_DECL(uint64_t, get_bytes_written, (void));
-NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap));
-NS_DECL(int, server_mode, (const or_options_t *options));
-NS_DECL(int, accounting_is_enabled, (const or_options_t *options));
+static double status_hb_tls_write_overhead_tls_get_write_overhead_ratio(void);
+static int status_hb_tls_write_overhead_we_are_hibernating(void);
+static int status_hb_tls_write_overhead_public_server_mode(
+ const or_options_t *options);
+static long status_hb_tls_write_overhead_get_uptime(void);
+static uint64_t status_hb_tls_write_overhead_get_bytes_read(void);
+static uint64_t status_hb_tls_write_overhead_get_bytes_written(void);
+static int status_hb_tls_write_overhead_server_mode(
+ const or_options_t *options);
+static int status_hb_tls_write_overhead_accounting_is_enabled(
+ const or_options_t *options);
static void
-NS(test_main)(void *arg)
+test_status_hb_tls_write_overhead(void *arg)
{
int expected, actual;
(void)arg;
- NS_MOCK(tls_get_write_overhead_ratio);
- NS_MOCK(we_are_hibernating);
- NS_MOCK(public_server_mode);
- NS_MOCK(get_uptime);
- NS_MOCK(get_bytes_read);
- NS_MOCK(get_bytes_written);
- NS_MOCK(logv);
- NS_MOCK(server_mode);
- NS_MOCK(accounting_is_enabled);
+ MOCK(tls_get_write_overhead_ratio,
+ status_hb_tls_write_overhead_tls_get_write_overhead_ratio);
+ MOCK(we_are_hibernating,
+ status_hb_tls_write_overhead_we_are_hibernating);
+ MOCK(public_server_mode,
+ status_hb_tls_write_overhead_public_server_mode);
+ MOCK(get_uptime,
+ status_hb_tls_write_overhead_get_uptime);
+ MOCK(get_bytes_read,
+ status_hb_tls_write_overhead_get_bytes_read);
+ MOCK(get_bytes_written,
+ status_hb_tls_write_overhead_get_bytes_written);
+ MOCK(server_mode,
+ status_hb_tls_write_overhead_server_mode);
+ MOCK(accounting_is_enabled,
+ status_hb_tls_write_overhead_accounting_is_enabled);
stats_n_data_cells_packaged = 0;
log_global_min_severity_ = LOG_DEBUG;
expected = 0;
+ setup_capture_of_logs(LOG_NOTICE);
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(CALLED(logv), OP_EQ, 2);
+ expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, "
+ "with 0 circuits open. "
+ "I've sent 0 kB and received 0 kB. "
+ "I've received 0 connections on IPv4 and 0 on IPv6. "
+ "I've made 0 connections with IPv4 and 0 with IPv6.\n");
+ expect_log_msg("Average packaged cell fullness: 100.000%. "
+ "TLS write overhead: 100%\n");
done:
- NS_UNMOCK(tls_get_write_overhead_ratio);
- NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(public_server_mode);
- NS_UNMOCK(get_uptime);
- NS_UNMOCK(get_bytes_read);
- NS_UNMOCK(get_bytes_written);
- NS_UNMOCK(logv);
- NS_UNMOCK(server_mode);
- NS_UNMOCK(accounting_is_enabled);
+ teardown_capture_of_logs();
+ UNMOCK(tls_get_write_overhead_ratio);
+ UNMOCK(we_are_hibernating);
+ UNMOCK(public_server_mode);
+ UNMOCK(get_uptime);
+ UNMOCK(get_bytes_read);
+ UNMOCK(get_bytes_written);
+ UNMOCK(server_mode);
+ UNMOCK(accounting_is_enabled);
}
static double
-NS(tls_get_write_overhead_ratio)(void)
+status_hb_tls_write_overhead_tls_get_write_overhead_ratio(void)
{
return 2.0;
}
static int
-NS(we_are_hibernating)(void)
+status_hb_tls_write_overhead_we_are_hibernating(void)
{
return 0;
}
static int
-NS(public_server_mode)(const or_options_t *options)
+status_hb_tls_write_overhead_public_server_mode(const or_options_t *options)
{
(void)options;
@@ -1013,65 +898,25 @@ NS(public_server_mode)(const or_options_t *options)
}
static long
-NS(get_uptime)(void)
+status_hb_tls_write_overhead_get_uptime(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_read)(void)
+status_hb_tls_write_overhead_get_bytes_read(void)
{
return 0;
}
static uint64_t
-NS(get_bytes_written)(void)
+status_hb_tls_write_overhead_get_bytes_written(void)
{
return 0;
}
-static void
-NS(logv)(int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap)
-{
- switch (CALLED(logv))
- {
- case 0:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Tor's uptime is %s, with %d circuits open. "
- "I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
- break;
- case 1:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Average packaged cell fullness: %2.3f%%. "
- "TLS write overhead: %.f%%");
- tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, OP_EQ, 1);
- tt_double_op(fabs(va_arg(ap, double) - 100.0), OP_LE, DBL_EPSILON);
- break;
- default:
- tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
- break;
- }
-
- done:
- CALLED(logv)++;
-}
-
static int
-NS(server_mode)(const or_options_t *options)
+status_hb_tls_write_overhead_server_mode(const or_options_t *options)
{
(void)options;
@@ -1079,24 +924,26 @@ NS(server_mode)(const or_options_t *options)
}
static int
-NS(accounting_is_enabled)(const or_options_t *options)
+status_hb_tls_write_overhead_accounting_is_enabled(const or_options_t *options)
{
(void)options;
return 0;
}
-#undef NS_SUBMODULE
-
struct testcase_t status_tests[] = {
- TEST_CASE(count_circuits),
- TEST_CASE(secs_to_uptime),
- TEST_CASE(bytes_to_usage),
- TEST_CASE_ASPECT(log_heartbeat, fails),
- TEST_CASE_ASPECT(log_heartbeat, simple),
- TEST_CASE_ASPECT(log_heartbeat, not_in_consensus),
- TEST_CASE_ASPECT(log_heartbeat, calls_log_accounting),
- TEST_CASE_ASPECT(log_heartbeat, packaged_cell_fullness),
- TEST_CASE_ASPECT(log_heartbeat, tls_write_overhead),
+ { "count_circuits", test_status_count_circuits, TT_FORK, NULL, NULL },
+ { "secs_to_uptime", test_status_secs_to_uptime, TT_FORK, NULL, NULL },
+ { "bytes_to_usage", test_status_bytes_to_usage, TT_FORK, NULL, NULL },
+ { "hb_fails", test_status_hb_fails, TT_FORK, NULL, NULL },
+ { "hb_simple", test_status_hb_simple, TT_FORK, NULL, NULL },
+ { "hb_not_in_consensus", test_status_hb_not_in_consensus,
+ TT_FORK, NULL, NULL },
+ { "hb_calls_log_accounting", test_status_hb_calls_log_accounting,
+ TT_FORK, NULL, NULL },
+ { "hb_packaged_cell_fullness", test_status_hb_packaged_cell_fullness,
+ TT_FORK, NULL, NULL },
+ { "hb_tls_write_overhead", test_status_hb_tls_write_overhead,
+ TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_storagedir.c b/src/test/test_storagedir.c
index 24e45c7428..eb3779cfee 100644
--- a/src/test/test_storagedir.c
+++ b/src/test/test_storagedir.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
diff --git a/src/test/test_switch_id.c b/src/test/test_switch_id.c
index 1c13ad3f24..f97af55d17 100644
--- a/src/test/test_switch_id.c
+++ b/src/test/test_switch_id.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2019, The Tor Project, Inc. */
+/* Copyright (c) 2015-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -127,7 +127,7 @@ main(int argc, char **argv)
fprintf(stderr, "This test is not supported on your OS.\n");
return 77;
-#else /* !(defined(_WIN32)) */
+#else /* !defined(_WIN32) */
const char *username;
const char *testname;
if (argc != 3) {
diff --git a/src/test/test_switch_id.sh b/src/test/test_switch_id.sh
index 79c44f2eb1..b13bf7602f 100755
--- a/src/test/test_switch_id.sh
+++ b/src/test/test_switch_id.sh
@@ -1,11 +1,11 @@
#!/bin/sh
-if test "`id -u`" != '0'; then
+if test "$(id -u)" != '0'; then
echo "This test only works when run as root. Skipping." >&2
exit 77
fi
-if test "`id -u nobody`" = ""; then
+if test "$(id -u nobody)" = ""; then
echo "This test requires that your system have a 'nobody' user. Sorry." >&2
exit 1
fi
diff --git a/src/test/test_threads.c b/src/test/test_threads.c
index 4a5ecc6fae..d5a1834aef 100644
--- a/src/test/test_threads.c
+++ b/src/test/test_threads.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -155,7 +155,7 @@ test_threads_basic(void *arg)
tor_mutex_free(thread_test_start2_);
}
-typedef struct cv_testinfo_s {
+typedef struct cv_testinfo_t {
tor_cond_t *cond;
tor_mutex_t *mutex;
int value;
diff --git a/src/test/test_token_bucket.c b/src/test/test_token_bucket.c
new file mode 100644
index 0000000000..cf315f2944
--- /dev/null
+++ b/src/test/test_token_bucket.c
@@ -0,0 +1,152 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_bwmgt.c
+ * \brief tests for bandwidth management / token bucket functions
+ */
+
+#define TOKEN_BUCKET_PRIVATE
+
+#include "core/or/or.h"
+#include "test/test.h"
+
+#include "lib/evloop/token_bucket.h"
+
+// an imaginary time, in timestamp units. Chosen so it will roll over.
+static const uint32_t START_TS = UINT32_MAX - 1000;
+static const uint32_t RATE = 10;
+static const uint32_t BURST = 50;
+
+static void
+test_token_bucket_ctr_init(void *arg)
+{
+ (void) arg;
+ token_bucket_ctr_t tb;
+
+ token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
+ tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
+ tt_uint_op(tb.cfg.burst, OP_EQ, BURST);
+ tt_uint_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS);
+ tt_int_op(tb.counter.bucket, OP_EQ, BURST);
+
+ done:
+ ;
+}
+
+static void
+test_token_bucket_ctr_adjust(void *arg)
+{
+ (void) arg;
+ token_bucket_ctr_t tb;
+
+ token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
+
+ /* Increase burst. */
+ token_bucket_ctr_adjust(&tb, RATE, BURST * 2);
+ tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
+ tt_uint_op(tb.counter.bucket, OP_EQ, BURST);
+ tt_uint_op(tb.cfg.burst, OP_EQ, BURST * 2);
+
+ /* Decrease burst but still above bucket value. */
+ token_bucket_ctr_adjust(&tb, RATE, BURST + 10);
+ tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
+ tt_uint_op(tb.counter.bucket, OP_EQ, BURST);
+ tt_uint_op(tb.cfg.burst, OP_EQ, BURST + 10);
+
+ /* Decrease burst below bucket value. */
+ token_bucket_ctr_adjust(&tb, RATE, BURST - 1);
+ tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
+ tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
+ tt_uint_op(tb.cfg.burst, OP_EQ, BURST - 1);
+
+ /* Change rate. */
+ token_bucket_ctr_adjust(&tb, RATE * 2, BURST);
+ tt_uint_op(tb.cfg.rate, OP_EQ, RATE * 2);
+ tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
+ tt_uint_op(tb.cfg.burst, OP_EQ, BURST);
+
+ done:
+ ;
+}
+
+static void
+test_token_bucket_ctr_dec(void *arg)
+{
+ (void) arg;
+ token_bucket_ctr_t tb;
+
+ token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
+
+ /* Simple decrement by one. */
+ tt_uint_op(0, OP_EQ, token_bucket_ctr_dec(&tb, 1));
+ tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
+
+ /* Down to 0. Becomes empty. */
+ tt_uint_op(true, OP_EQ, token_bucket_ctr_dec(&tb, BURST - 1));
+ tt_uint_op(tb.counter.bucket, OP_EQ, 0);
+
+ /* Reset and try to underflow. */
+ token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
+ tt_uint_op(true, OP_EQ, token_bucket_ctr_dec(&tb, BURST + 1));
+ tt_int_op(tb.counter.bucket, OP_EQ, -1);
+
+ /* Keep underflowing shouldn't flag the bucket as empty. */
+ tt_uint_op(false, OP_EQ, token_bucket_ctr_dec(&tb, BURST));
+ tt_int_op(tb.counter.bucket, OP_EQ, - (int32_t) (BURST + 1));
+
+ done:
+ ;
+}
+
+static void
+test_token_bucket_ctr_refill(void *arg)
+{
+ (void) arg;
+ token_bucket_ctr_t tb;
+
+ token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
+
+ /* Reduce of half the bucket and let a single second go before refill. */
+ token_bucket_ctr_dec(&tb, BURST / 2);
+ tt_int_op(tb.counter.bucket, OP_EQ, BURST / 2);
+ token_bucket_ctr_refill(&tb, START_TS + 1);
+ tt_int_op(tb.counter.bucket, OP_EQ, (BURST / 2) + RATE);
+ tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 1);
+
+ /* No time change, nothing should move. */
+ token_bucket_ctr_refill(&tb, START_TS + 1);
+ tt_int_op(tb.counter.bucket, OP_EQ, (BURST / 2) + RATE);
+ tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 1);
+
+ /* Add 99 seconds, bucket should be back to a full BURST. */
+ token_bucket_ctr_refill(&tb, START_TS + 99);
+ tt_int_op(tb.counter.bucket, OP_EQ, BURST);
+ tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 99);
+
+ /* Empty bucket at once. */
+ token_bucket_ctr_dec(&tb, BURST);
+ tt_int_op(tb.counter.bucket, OP_EQ, 0);
+ /* On second passes. */
+ token_bucket_ctr_refill(&tb, START_TS + 100);
+ tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 100);
+ tt_int_op(tb.counter.bucket, OP_EQ, RATE);
+ /* A second second passes. */
+ token_bucket_ctr_refill(&tb, START_TS + 101);
+ tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 101);
+ tt_int_op(tb.counter.bucket, OP_EQ, RATE * 2);
+
+ done:
+ ;
+}
+
+#define TOKEN_BUCKET(name) \
+ { #name, test_token_bucket_ ## name , 0, NULL, NULL }
+
+struct testcase_t token_bucket_tests[] = {
+ TOKEN_BUCKET(ctr_init),
+ TOKEN_BUCKET(ctr_adjust),
+ TOKEN_BUCKET(ctr_dec),
+ TOKEN_BUCKET(ctr_refill),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index 853abc4f91..12ba873650 100644
--- a/src/test/test_tortls.c
+++ b/src/test/test_tortls.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TORTLS_PRIVATE
@@ -225,12 +225,12 @@ test_tortls_tor_tls_get_error(void *data)
done:
UNMOCK(tor_tls_cert_matches_key);
- NS_UNMOCK(logv);
+ UNMOCK(logv);
crypto_pk_free(key1);
crypto_pk_free(key2);
tor_tls_free(tls);
}
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
static void
test_tortls_x509_cert_get_id_digests(void *ignored)
@@ -347,7 +347,7 @@ test_tortls_server_got_renegotiate(void *ignored)
done:
tor_free(tls);
}
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
static void
test_tortls_evaluate_ecgroup_for_tls(void *ignored)
@@ -598,7 +598,7 @@ struct testcase_t tortls_tests[] = {
LOCAL_TEST_CASE(get_forced_write_size, 0),
LOCAL_TEST_CASE(used_v1_handshake, TT_FORK),
LOCAL_TEST_CASE(server_got_renegotiate, 0),
-#endif
+#endif /* defined(ENABLE_OPENSSL) */
LOCAL_TEST_CASE(evaluate_ecgroup_for_tls, 0),
LOCAL_TEST_CASE(double_init, TT_FORK),
LOCAL_TEST_CASE(address, TT_FORK),
diff --git a/src/test/test_tortls.h b/src/test/test_tortls.h
index 1a8b117d0f..21c6fa0a8f 100644
--- a/src/test/test_tortls.h
+++ b/src/test/test_tortls.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TEST_TORTLS_H
@@ -10,4 +10,4 @@ extern const char *notCompletelyValidCertString;
extern const char *validCertString;
extern const char *caCertString;
-#endif
+#endif /* !defined(TEST_TORTLS_H) */
diff --git a/src/test/test_tortls_openssl.c b/src/test/test_tortls_openssl.c
index 81c65d7446..c1a87fbb4f 100644
--- a/src/test/test_tortls_openssl.c
+++ b/src/test/test_tortls_openssl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TORTLS_PRIVATE
@@ -16,7 +16,7 @@
/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
* srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
-DISABLE_GCC_WARNING(redundant-decls)
+DISABLE_GCC_WARNING("-Wredundant-decls")
#include <openssl/opensslv.h>
@@ -29,7 +29,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/evp.h>
#include <openssl/bn.h>
-ENABLE_GCC_WARNING(redundant-decls)
+ENABLE_GCC_WARNING("-Wredundant-decls")
#include "core/or/or.h"
#include "lib/log/log.h"
@@ -46,8 +46,6 @@ ENABLE_GCC_WARNING(redundant-decls)
#include "test/log_test_helpers.h"
#include "test/test_tortls.h"
-#define NS_MODULE tortls
-
#ifndef HAVE_SSL_STATE
#define OPENSSL_OPAQUE
#endif
@@ -123,8 +121,6 @@ test_tortls_tor_tls_new(void *data)
tor_tls_free_all();
}
-#define NS_MODULE tortls
-
static void
library_init(void)
{
@@ -133,7 +129,7 @@ library_init(void)
#else
SSL_library_init();
SSL_load_error_strings();
-#endif
+#endif /* defined(OPENSSL_1_1_API) */
}
static void
@@ -476,7 +472,7 @@ fake_x509_free(X509 *cert)
tor_free(cert);
}
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 7f07370998..f567a18367 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1,27 +1,28 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
-#define COMPAT_PRIVATE
#define COMPAT_TIME_PRIVATE
-#define CONTROL_PRIVATE
-#define UTIL_PRIVATE
#define UTIL_MALLOC_PRIVATE
-#define SOCKET_PRIVATE
-#define SUBPROCESS_PRIVATE
+#define PROCESS_WIN32_PRIVATE
+#define TIME_FMT_PRIVATE
#include "lib/testsupport/testsupport.h"
#include "core/or/or.h"
-#include "lib/container/buffers.h"
+#include "lib/buf/buffers.h"
#include "app/config/config.h"
#include "feature/control/control.h"
+#include "feature/control/control_proto.h"
#include "feature/client/transports.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/defs/time.h"
#include "test/test.h"
+#include "test/test_helpers.h"
#include "lib/memarea/memarea.h"
#include "lib/process/waitpid.h"
+#include "lib/process/process_win32.h"
#include "test/log_test_helpers.h"
#include "lib/compress/compress.h"
#include "lib/compress/compress_zstd.h"
@@ -30,8 +31,8 @@
#include "lib/fs/winlib.h"
#include "lib/process/env.h"
#include "lib/process/pidfile.h"
-#include "lib/process/subprocess.h"
#include "lib/intmath/weakrng.h"
+#include "lib/intmath/muldiv.h"
#include "lib/thread/numcpus.h"
#include "lib/math/fp.h"
#include "lib/math/laplace.h"
@@ -39,6 +40,7 @@
#include "lib/time/tvdiff.h"
#include "lib/encoding/confline.h"
#include "lib/net/socketpair.h"
+#include "lib/malloc/map_anon.h"
#ifdef HAVE_PWD_H
#include <pwd.h>
@@ -58,6 +60,12 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
#ifdef _WIN32
#include <tchar.h>
@@ -66,16 +74,45 @@
#include <ctype.h>
#include <float.h>
+/* These platforms don't have meaningful pwdb or homedirs. */
+#if defined(_WIN32) || defined(__ANDROID__)
+#define DISABLE_PWDB_TESTS
+#endif
+
+static void set_file_mtime(const char *fname, time_t when);
+
#define INFINITY_DBL ((double)INFINITY)
#define NAN_DBL ((double)NAN)
+/** Test the tor_isinf() wrapper */
+static void
+test_tor_isinf(void *arg)
+{
+ (void) arg;
+
+ tt_assert(tor_isinf(INFINITY_DBL));
+
+ tt_assert(!tor_isinf(NAN_DBL));
+ tt_assert(!tor_isinf(DBL_EPSILON));
+ tt_assert(!tor_isinf(DBL_MAX));
+ tt_assert(!tor_isinf(DBL_MIN));
+
+ tt_assert(!tor_isinf(0.0));
+ tt_assert(!tor_isinf(0.1));
+ tt_assert(!tor_isinf(3));
+ tt_assert(!tor_isinf(3.14));
+
+ done:
+ ;
+}
+
/* XXXX this is a minimal wrapper to make the unit tests compile with the
* changed tor_timegm interface. */
static time_t
tor_timegm_wrapper(const struct tm *tm)
{
time_t t;
- if (tor_timegm(tm, &t) < 0)
+ if (tor_timegm_impl(tm, &t) < 0)
return -1;
return t;
}
@@ -322,6 +359,56 @@ test_util_write_chunks_to_file(void *arg)
tor_free(temp_str);
}
+/* Test write_str_to_file_if_not_equal(). */
+static void
+test_util_write_str_if_changed(void *arg)
+{
+ (void)arg;
+ char *fname = tor_strdup(get_fname("write_if_changed"));
+ char *s = NULL;
+ int rv;
+ const char str1[] = "The wombat lives across the seas";
+ const char str2[] = "Among the far Antipodes"; /* -- Ogden Nash */
+
+ /* We can create files. */
+ rv = write_str_to_file_if_not_equal(fname, str1);
+ tt_int_op(rv, OP_EQ, 0);
+ s = read_file_to_str(fname, 0, NULL);
+ tt_str_op(s, OP_EQ, str1);
+ tor_free(s);
+
+ /* We can replace files. */
+ rv = write_str_to_file_if_not_equal(fname, str2);
+ tt_int_op(rv, OP_EQ, 0);
+ s = read_file_to_str(fname, 0, NULL);
+ tt_str_op(s, OP_EQ, str2);
+ tor_free(s);
+
+ /* Make sure we don't replace files when they're equal. (That's the whole
+ * point of the function we're testing. */
+ /* First, change the mtime of the file so that we can tell whether we
+ * replaced it. */
+ const time_t now = time(NULL);
+ const time_t five_sec_ago = now - 5;
+ set_file_mtime(fname, five_sec_ago);
+ rv = write_str_to_file_if_not_equal(fname, str2);
+ tt_int_op(rv, OP_EQ, 0);
+ /* Make sure that the file's mtime is unchanged... */
+ struct stat st;
+ rv = stat(fname, &st);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_i64_op(st.st_mtime, OP_EQ, five_sec_ago);
+ /* And make sure its contents are unchanged. */
+ s = read_file_to_str(fname, 0, NULL);
+ tt_str_op(s, OP_EQ, str2);
+ tor_free(s);
+
+ done:
+ tor_free(fname);
+ tor_free(s);
+}
+
+#ifndef COCCI
#define _TFE(a, b, f) tt_int_op((a).f, OP_EQ, (b).f)
/** test the minimum set of struct tm fields needed for a unique epoch value
* this is also the set we use to test tor_timegm */
@@ -334,6 +421,7 @@ test_util_write_chunks_to_file(void *arg)
_TFE(a, b, tm_min ); \
_TFE(a, b, tm_sec ); \
TT_STMT_END
+#endif /* !defined(COCCI) */
static void
test_util_time(void *arg)
@@ -452,7 +540,6 @@ test_util_time(void *arg)
/* Assume tv_usec is an unsigned integer until proven otherwise */
#define TV_USEC_MAX UINT_MAX
-#define TOR_USEC_PER_SEC 1000000
/* Overflows in the result type */
@@ -718,7 +805,7 @@ test_util_time(void *arg)
#if SIZEOF_TIME_T == 4
setup_full_capture_of_logs(LOG_WARN);
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
- expect_single_log_msg_containing("Result does not fit in tor_timegm");
+ //expect_single_log_msg_containing("Result does not fit in tor_timegm");
teardown_capture_of_logs();
#elif SIZEOF_TIME_T == 8
t_res = 2178252895UL;
@@ -732,17 +819,16 @@ test_util_time(void *arg)
/* The below tests will all cause a BUG message, so we capture, suppress,
* and detect. */
#define CAPTURE() do { \
+ teardown_capture_of_logs(); \
setup_full_capture_of_logs(LOG_WARN); \
} while (0)
#define CHECK_TIMEGM_WARNING(msg) do { \
expect_single_log_msg_containing(msg); \
- teardown_capture_of_logs(); \
} while (0)
#define CHECK_POSSIBLE_EINVAL() do { \
if (mock_saved_log_n_entries()) { \
expect_single_log_msg_containing("Invalid argument"); \
} \
- teardown_capture_of_logs(); \
} while (0)
#define CHECK_TIMEGM_ARG_OUT_OF_RANGE(msg) \
@@ -1131,7 +1217,7 @@ test_util_time(void *arg)
t_res = 0;
CAPTURE();
i = parse_rfc1123_time(timestr, &t_res);
- CHECK_TIMEGM_WARNING("does not fit in tor_timegm");
+ // CHECK_TIMEGM_WARNING("does not fit in tor_timegm");
tt_int_op(-1,OP_EQ, i);
#elif SIZEOF_TIME_T == 8
tt_str_op("Wed, 17 Feb 2038 06:13:20 GMT",OP_EQ, timestr);
@@ -1210,7 +1296,7 @@ test_util_time(void *arg)
CAPTURE();
i = parse_iso_time("2038-02-17 06:13:20", &t_res);
tt_int_op(-1,OP_EQ, i);
- CHECK_TIMEGM_WARNING("does not fit in tor_timegm");
+ //CHECK_TIMEGM_WARNING("does not fit in tor_timegm");
#elif SIZEOF_TIME_T == 8
i = parse_iso_time("2038-02-17 06:13:20", &t_res);
tt_int_op(0,OP_EQ, i);
@@ -1393,7 +1479,7 @@ test_util_parse_http_time(void *arg)
setup_full_capture_of_logs(LOG_WARN);
tt_int_op(0,OP_EQ,parse_http_time("Wed, 17 Feb 2038 06:13:20 GMT", &a_time));
tt_int_op((time_t)-1,OP_EQ, tor_timegm(&a_time));
- expect_single_log_msg_containing("does not fit in tor_timegm");
+ //expect_single_log_msg_containing("does not fit in tor_timegm");
teardown_capture_of_logs();
#elif SIZEOF_TIME_T == 8
tt_int_op(0,OP_EQ,parse_http_time("Wed, 17 Feb 2038 06:13:20 GMT", &a_time));
@@ -1416,6 +1502,28 @@ test_util_parse_http_time(void *arg)
}
static void
+test_util_timegm_real(void *arg)
+{
+ (void)arg;
+ /* Get the real timegm again! We're not testing our impl; we want the
+ * one that will actually get called. */
+#undef tor_timegm
+
+ /* Now check: is timegm the real inverse of gmtime? */
+ time_t now = time(NULL), time2=0;
+ struct tm tm, *p;
+ p = tor_gmtime_r(&now, &tm);
+ tt_ptr_op(p, OP_NE, NULL);
+
+ int r = tor_timegm(&tm, &time2);
+ tt_int_op(r, OP_EQ, 0);
+ tt_i64_op((int64_t) now, OP_EQ, (int64_t) time2);
+
+ done:
+ ;
+}
+
+static void
test_util_config_line(void *arg)
{
char buf[1024];
@@ -1864,7 +1972,57 @@ test_util_config_line_crlf(void *arg)
tor_free(k); tor_free(v);
}
-#ifndef _WIN32
+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)
{
@@ -1961,7 +2119,7 @@ test_util_expand_filename(void *arg)
done:
tor_free(str);
}
-#endif /* !defined(_WIN32) */
+#endif /* !defined(DISABLE_PWDB_TESTS) */
/** Test tor_escape_str_for_pt_args(). */
static void
@@ -2106,14 +2264,14 @@ test_util_strmisc(void *arg)
/* Test mem_is_zero */
memset(buf,0,128);
buf[128] = 'x';
- tt_assert(tor_mem_is_zero(buf, 10));
- tt_assert(tor_mem_is_zero(buf, 20));
- tt_assert(tor_mem_is_zero(buf, 128));
- tt_assert(!tor_mem_is_zero(buf, 129));
+ tt_assert(fast_mem_is_zero(buf, 10));
+ tt_assert(fast_mem_is_zero(buf, 20));
+ tt_assert(fast_mem_is_zero(buf, 128));
+ tt_assert(!fast_mem_is_zero(buf, 129));
buf[60] = (char)255;
- tt_assert(!tor_mem_is_zero(buf, 128));
+ tt_assert(!fast_mem_is_zero(buf, 128));
buf[0] = (char)1;
- tt_assert(!tor_mem_is_zero(buf, 10));
+ tt_assert(!fast_mem_is_zero(buf, 10));
/* Test 'escaped' */
tt_ptr_op(escaped(NULL), OP_EQ, NULL);
@@ -2227,15 +2385,6 @@ test_util_strmisc(void *arg)
tt_int_op(strcmp_opt(NULL, "foo"), OP_LT, 0);
tt_int_op(strcmp_opt("foo", NULL), OP_GT, 0);
- /* Test strcmp_len */
- tt_int_op(strcmp_len("foo", "bar", 3), OP_GT, 0);
- tt_int_op(strcmp_len("foo", "bar", 2), OP_LT, 0);
- tt_int_op(strcmp_len("foo2", "foo1", 4), OP_GT, 0);
- tt_int_op(strcmp_len("foo2", "foo1", 3), OP_LT, 0); /* Really stop at len */
- tt_int_op(strcmp_len("foo2", "foo", 3), OP_EQ, 0); /* Really stop at len */
- tt_int_op(strcmp_len("blah", "", 4), OP_GT, 0);
- tt_int_op(strcmp_len("blah", "", 0), OP_EQ, 0);
-
done:
tor_free(cp_tmp);
}
@@ -3817,7 +3966,7 @@ test_util_memarea(void *arg)
tt_int_op(((uintptr_t)p3) % sizeof(void*),OP_EQ, 0);
tt_assert(!memarea_owns_ptr(area, p3+8192));
tt_assert(!memarea_owns_ptr(area, p3+30));
- tt_assert(tor_mem_is_zero(p2, 52));
+ tt_assert(fast_mem_is_zero(p2, 52));
/* Make sure we don't overalign. */
p1 = memarea_alloc(area, 1);
p2 = memarea_alloc(area, 1);
@@ -4058,6 +4207,31 @@ test_util_find_str_at_start_of_line(void *ptr)
}
static void
+test_util_tor_strreplacechar(void *ptr)
+{
+ (void)ptr;
+ char empty[] = "";
+ char not_contain[] = "bbb";
+ char contains[] = "bab";
+ char contains_all[] = "aaa";
+
+ tor_strreplacechar(empty, 'a', 'b');
+ tt_str_op(empty, OP_EQ, "");
+
+ tor_strreplacechar(not_contain, 'a', 'b');
+ tt_str_op(not_contain, OP_EQ, "bbb");
+
+ tor_strreplacechar(contains, 'a', 'b');
+ tt_str_op(contains, OP_EQ, "bbb");
+
+ tor_strreplacechar(contains_all, 'a', 'b');
+ tt_str_op(contains_all, OP_EQ, "bbb");
+
+ done:
+ ;
+}
+
+static void
test_util_string_is_C_identifier(void *ptr)
{
(void)ptr;
@@ -4098,6 +4272,13 @@ test_util_string_is_utf8(void *ptr)
tt_int_op(1, OP_EQ, string_is_utf8("ascii\x7f\n", 7));
tt_int_op(1, OP_EQ, string_is_utf8("Risqu\u00e9=1", 9));
+ /* Test the utf8_no_bom function */
+ tt_int_op(0, OP_EQ, string_is_utf8_no_bom("\uFEFF", 3));
+ tt_int_op(0, OP_EQ, string_is_utf8_no_bom("\uFFFE", 3));
+ tt_int_op(0, OP_EQ, string_is_utf8_no_bom("\uFEFFlove", 7));
+ tt_int_op(1, OP_EQ, string_is_utf8_no_bom("loveandrespect",
+ strlen("loveandrespect")));
+
// Validate exactly 'len' bytes.
tt_int_op(0, OP_EQ, string_is_utf8("\0\x80", 2));
tt_int_op(0, OP_EQ, string_is_utf8("Risqu\u00e9=1", 6));
@@ -4125,10 +4306,43 @@ test_util_string_is_utf8(void *ptr)
tt_int_op(0, OP_EQ, string_is_utf8("\xed\xbf\xbf", 3));
tt_int_op(1, OP_EQ, string_is_utf8("\xee\x80\x80", 3));
- // The maximum legal codepoint, 10FFFF.
+ // The minimum legal codepoint, 0x00.
+ tt_int_op(1, OP_EQ, string_is_utf8("\0", 1));
+
+ // The maximum legal codepoint, 0x10FFFF.
tt_int_op(1, OP_EQ, string_is_utf8("\xf4\x8f\xbf\xbf", 4));
tt_int_op(0, OP_EQ, string_is_utf8("\xf4\x90\x80\x80", 4));
+ /* Test cases that vary between programming languages /
+ * UTF-8 implementations.
+ * Source: POC||GTFO 19, page 43
+ * https://www.alchemistowl.org/pocorgtfo/
+ */
+
+ // Invalid (in most implementations)
+ // surrogate
+ tt_int_op(0, OP_EQ, string_is_utf8("\xed\xa0\x81", 3));
+ // nullsurrog
+ tt_int_op(0, OP_EQ, string_is_utf8("\x30\x00\xed\xa0\x81", 5));
+ // threehigh
+ tt_int_op(0, OP_EQ, string_is_utf8("\xed\xbf\xbf", 3));
+ // fourhigh
+ tt_int_op(0, OP_EQ, string_is_utf8("\xf4\x90\xbf\xbf", 4));
+ // fivebyte
+ tt_int_op(0, OP_EQ, string_is_utf8("\xfb\x80\x80\x80\x80", 5));
+ // sixbyte
+ tt_int_op(0, OP_EQ, string_is_utf8("\xfd\x80\x80\x80\x80", 5));
+ // sixhigh
+ tt_int_op(0, OP_EQ, string_is_utf8("\xfd\xbf\xbf\xbf\xbf", 5));
+
+ // Valid (in most implementations)
+ // fourbyte
+ tt_int_op(1, OP_EQ, string_is_utf8("\xf0\x90\x8d\x88", 4));
+ // fourbyte2
+ tt_int_op(1, OP_EQ, string_is_utf8("\xf0\xbf\xbf\xbf", 4));
+ // nullbyte
+ tt_int_op(1, OP_EQ, string_is_utf8("\x30\x31\x32\x00\x33", 5));
+
done:
;
}
@@ -4244,6 +4458,438 @@ test_util_listdir(void *ptr)
}
static void
+test_util_glob(void *ptr)
+{
+ (void)ptr;
+
+#ifdef HAVE_GLOB
+ smartlist_t *results = NULL;
+ int r, i;
+ char *dir1 = NULL, *dir2 = NULL, *forbidden = NULL, *dirname = NULL;
+ char *expected = NULL, *pattern = NULL;
+ // used for cleanup
+ char *dir1_forbidden = NULL, *dir2_forbidden = NULL;
+ char *forbidden_forbidden = NULL;
+
+ dirname = tor_strdup(get_fname("test_glob"));
+ tt_ptr_op(dirname, OP_NE, NULL);
+
+#ifdef _WIN32
+ r = mkdir(dirname);
+#else
+ r = mkdir(dirname, 0700);
+#endif
+ if (r) {
+ fprintf(stderr, "Can't create directory %s:", dirname);
+ perror("");
+ exit(1);
+ }
+
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dirname));
+ tor_asprintf(&dir1, "%s"PATH_SEPARATOR"dir1", dirname);
+ tor_asprintf(&dir1_forbidden,
+ "%s"PATH_SEPARATOR"dir1"PATH_SEPARATOR"forbidden", dirname);
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dir1));
+ tor_asprintf(&dir2, "%s"PATH_SEPARATOR"dir2", dirname);
+ tor_asprintf(&dir2_forbidden,
+ "%s"PATH_SEPARATOR"dir2"PATH_SEPARATOR"forbidden", dirname);
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dir2));
+ tor_asprintf(&forbidden, "%s"PATH_SEPARATOR"forbidden", dirname);
+ tor_asprintf(&forbidden_forbidden,
+ "%s"PATH_SEPARATOR"forbidden"PATH_SEPARATOR"forbidden",dirname);
+#ifndef _WIN32
+ tt_int_op(0, OP_EQ, chmod(forbidden, 0700));
+#endif
+ tt_int_op(0, OP_EQ, create_test_directory_structure(forbidden));
+#ifndef _WIN32
+ tt_int_op(0, OP_EQ, chmod(forbidden, 0));
+#endif
+
+#define TEST(input) \
+ do { \
+ tor_asprintf(&pattern, "%s"PATH_SEPARATOR"%s", dirname, input); \
+ results = tor_glob(pattern); \
+ tor_free(pattern); \
+ tt_assert(results); \
+ smartlist_sort_strings(results); \
+ } while (0);
+
+#define EXPECT(result) \
+ do { \
+ tt_int_op(smartlist_len(results), OP_EQ, \
+ sizeof(result)/sizeof(*result)); \
+ i = 0; \
+ SMARTLIST_FOREACH_BEGIN(results, const char *, f) { \
+ tor_asprintf(&expected, "%s"PATH_SEPARATOR"%s", dirname, result[i]); \
+ tt_str_op(f, OP_EQ, expected); \
+ i++; \
+ tor_free(expected); \
+ } SMARTLIST_FOREACH_END(f); \
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f)); \
+ smartlist_free(results); \
+ } while (0);
+
+#define EXPECT_EMPTY() \
+ do { \
+ tt_int_op(smartlist_len(results), OP_EQ, 0); \
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f)); \
+ smartlist_free(results); \
+ } while (0);
+
+ // wildcards at beginning
+ const char *results_test1[] = {"dir2", "file2"};
+ TEST("*2");
+ EXPECT(results_test1);
+
+ // wildcards at end
+ const char *results_test2[] = {"dir1", "dir2"};
+ TEST("d*");
+ EXPECT(results_test2);
+
+ // wildcards at beginning and end
+#ifdef _WIN32
+ // dot files are not ignored on Windows
+ const char *results_test3[] = {".test-hidden", "dir1", "dir2", "file1",
+ "file2", "forbidden"};
+#else
+ const char *results_test3[] = {"dir1", "dir2", "file1", "file2",
+ "forbidden"};
+#endif
+ TEST("*i*");
+ EXPECT(results_test3);
+
+ // wildcards in middle
+ const char *results_test4[] = {"dir1", "dir2"};
+ TEST("d?r*");
+ EXPECT(results_test4);
+
+ // test file that does not exist
+ TEST("not-exist");
+ EXPECT_EMPTY();
+
+ // test wildcard that matches nothing
+ TEST("*not-exist*");
+ EXPECT_EMPTY();
+
+ // test path separator at end - no wildcards
+ const char *results_test7[] = {"dir1"};
+ TEST("dir1");
+ EXPECT(results_test7);
+
+ const char *results_test8[] = {"dir1"};
+ TEST("dir1"PATH_SEPARATOR);
+ EXPECT(results_test8);
+
+ const char *results_test9[] = {"file1"};
+ TEST("file1");
+ EXPECT(results_test9);
+
+#if defined(__APPLE__) || defined(__darwin__) || \
+ defined(__FreeBSD__) || defined(__NetBSD__) || defined(OpenBSD)
+ TEST("file1"PATH_SEPARATOR);
+ EXPECT_EMPTY();
+#else
+ const char *results_test10[] = {"file1"};
+ TEST("file1"PATH_SEPARATOR);
+ EXPECT(results_test10);
+#endif
+
+ // test path separator at end - with wildcards and linux path separator
+ const char *results_test11[] = {"dir1", "dir2", "forbidden"};
+ TEST("*/");
+ EXPECT(results_test11);
+
+#ifdef _WIN32
+ // dot files are not ignored on Windows
+ const char *results_test12[] = {".test-hidden", "dir1", "dir2", "empty",
+ "file1", "file2", "forbidden"};
+#else
+ const char *results_test12[] = {"dir1", "dir2", "empty", "file1", "file2",
+ "forbidden"};
+#endif
+ TEST("*");
+ EXPECT(results_test12);
+
+ // wildcards on folder and file and linux path separator
+ const char *results_test13[] = {"dir1"PATH_SEPARATOR"dir1",
+ "dir1"PATH_SEPARATOR"dir2",
+ "dir1"PATH_SEPARATOR"file1",
+ "dir1"PATH_SEPARATOR"file2",
+ "dir2"PATH_SEPARATOR"dir1",
+ "dir2"PATH_SEPARATOR"dir2",
+ "dir2"PATH_SEPARATOR"file1",
+ "dir2"PATH_SEPARATOR"file2"};
+ TEST("?i*/?i*");
+ EXPECT(results_test13);
+
+ // wildcards on file only
+ const char *results_test14[] = {"dir1"PATH_SEPARATOR"dir1",
+ "dir1"PATH_SEPARATOR"dir2",
+ "dir1"PATH_SEPARATOR"file1",
+ "dir1"PATH_SEPARATOR"file2"};
+ TEST("dir1"PATH_SEPARATOR"?i*");
+ EXPECT(results_test14);
+
+ // wildcards on folder only
+ const char *results_test15[] = {"dir1"PATH_SEPARATOR"file1",
+ "dir2"PATH_SEPARATOR"file1"};
+ TEST("?i*"PATH_SEPARATOR"file1");
+ EXPECT(results_test15);
+
+ // wildcards after file name
+ TEST("file1"PATH_SEPARATOR"*");
+ EXPECT_EMPTY();
+
+#ifndef _WIN32
+ // test wildcard escaping
+ TEST("\\*");
+ EXPECT_EMPTY();
+
+ if (getuid() != 0) {
+ // test forbidden directory, if we're not root.
+ // (Root will be able to see this directory anyway.)
+ tor_asprintf(&pattern, "%s"PATH_SEPARATOR"*"PATH_SEPARATOR"*", dirname);
+ results = tor_glob(pattern);
+ tor_free(pattern);
+ tt_assert(!results);
+ }
+#endif
+
+#undef TEST
+#undef EXPECT
+#undef EXPECT_EMPTY
+
+ done:
+#ifndef _WIN32
+ (void) chmod(forbidden, 0700);
+ (void) chmod(dir1_forbidden, 0700);
+ (void) chmod(dir2_forbidden, 0700);
+ (void) chmod(forbidden_forbidden, 0700);
+#endif
+ tor_free(dir1);
+ tor_free(dir2);
+ tor_free(forbidden);
+ tor_free(dirname);
+ tor_free(dir1_forbidden);
+ tor_free(dir2_forbidden);
+ tor_free(forbidden_forbidden);
+ tor_free(expected);
+ tor_free(pattern);
+ if (results) {
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f));
+ smartlist_free(results);
+ }
+#else
+ tt_skip();
+ done:
+ return;
+#endif
+}
+
+static void
+test_util_get_glob_opened_files(void *ptr)
+{
+ (void)ptr;
+
+#ifdef HAVE_GLOB
+ smartlist_t *results = NULL;
+ int r, i;
+ char *dir1 = NULL, *dir2 = NULL, *forbidden = NULL, *dirname = NULL;
+ char *expected = NULL, *pattern = NULL;
+ // used for cleanup
+ char *dir1_forbidden = NULL, *dir2_forbidden = NULL;
+ char *forbidden_forbidden = NULL;
+
+ dirname = tor_strdup(get_fname("test_get_glob_opened_files"));
+ tt_ptr_op(dirname, OP_NE, NULL);
+
+#ifdef _WIN32
+ r = mkdir(dirname);
+#else
+ r = mkdir(dirname, 0700);
+#endif
+ if (r) {
+ fprintf(stderr, "Can't create directory %s:", dirname);
+ perror("");
+ exit(1);
+ }
+
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dirname));
+ tor_asprintf(&dir1, "%s"PATH_SEPARATOR"dir1", dirname);
+ tor_asprintf(&dir1_forbidden,
+ "%s"PATH_SEPARATOR"dir1"PATH_SEPARATOR"forbidden", dirname);
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dir1));
+ tor_asprintf(&dir2, "%s"PATH_SEPARATOR"dir2", dirname);
+ tor_asprintf(&dir2_forbidden,
+ "%s"PATH_SEPARATOR"dir2"PATH_SEPARATOR"forbidden", dirname);
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dir2));
+ tor_asprintf(&forbidden, "%s"PATH_SEPARATOR"forbidden", dirname);
+ tor_asprintf(&forbidden_forbidden,
+ "%s"PATH_SEPARATOR"forbidden"PATH_SEPARATOR"forbidden",dirname);
+#ifndef _WIN32
+ chmod(forbidden, 0700);
+#endif
+ tt_int_op(0, OP_EQ, create_test_directory_structure(forbidden));
+#ifndef _WIN32
+ chmod(forbidden, 0);
+#endif
+
+#define TEST(input) \
+ do { \
+ if (*input) { \
+ tor_asprintf(&pattern, "%s"PATH_SEPARATOR"%s", dirname, input); \
+ } else { /* do not add path separator if empty string */ \
+ tor_asprintf(&pattern, "%s", dirname); \
+ } \
+ results = get_glob_opened_files(pattern); \
+ tor_free(pattern); \
+ tt_assert(results); \
+ smartlist_sort_strings(results); \
+ } while (0);
+
+#define EXPECT(result) \
+ do { \
+ tt_int_op(smartlist_len(results), OP_EQ, \
+ sizeof(result)/sizeof(*result)); \
+ i = 0; \
+ SMARTLIST_FOREACH_BEGIN(results, const char *, f) { \
+ if (*result[i]) { \
+ tor_asprintf(&expected, "%s"PATH_SEPARATOR"%s", dirname, result[i]); \
+ } else { /* do not add path separator if empty string */ \
+ tor_asprintf(&expected, "%s", dirname); \
+ } \
+ tt_str_op(f, OP_EQ, expected); \
+ i++; \
+ tor_free(expected); \
+ } SMARTLIST_FOREACH_END(f); \
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f)); \
+ smartlist_free(results); \
+ } while (0);
+
+#define EXPECT_EMPTY() \
+ do { \
+ tt_int_op(smartlist_len(results), OP_EQ, 0); \
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f)); \
+ smartlist_free(results); \
+ } while (0);
+
+ // all files on folder
+ const char *results_test1[] = {""}; // only the folder is read
+ TEST("*");
+ EXPECT(results_test1);
+
+ // same as before but ending in path separator
+ const char *results_test2[] = {""}; // only the folder is read
+ TEST("*"PATH_SEPARATOR);
+ EXPECT(results_test2);
+
+ // wildcards in multiple path components
+#ifndef _WIN32
+ const char *results_test3[] = {"", "dir1", "dir2", "empty", "file1", "file2",
+ "forbidden"};
+#else
+ // dot files are not special on windows
+ const char *results_test3[] = {"", ".test-hidden", "dir1", "dir2", "empty",
+ "file1", "file2", "forbidden"};
+#endif
+ TEST("*"PATH_SEPARATOR"*");
+ EXPECT(results_test3);
+
+ // same as before but ending in path separator
+#ifndef _WIN32
+ const char *results_test4[] = {"", "dir1", "dir2", "empty", "file1", "file2",
+ "forbidden"};
+#else
+ // dot files are not special on windows
+ const char *results_test4[] = {"", ".test-hidden", "dir1", "dir2", "empty",
+ "file1", "file2", "forbidden"};
+#endif
+ TEST("*"PATH_SEPARATOR"*"PATH_SEPARATOR);
+ EXPECT(results_test4);
+
+ // no glob - folder
+ TEST("");
+ EXPECT_EMPTY();
+
+ // same as before but ending in path separator
+ TEST(PATH_SEPARATOR);
+ EXPECT_EMPTY();
+
+ // no glob - file
+ TEST("file1");
+ EXPECT_EMPTY();
+
+ // same as before but ending in path separator and linux path separator
+ TEST("file1/");
+ EXPECT_EMPTY();
+
+ // file but with wildcard after
+ const char *results_test9[] = {"file1"};
+ TEST("file1"PATH_SEPARATOR"*");
+ EXPECT(results_test9);
+
+ // dir inside dir and linux path separator
+ TEST("dir1/dir1");
+ EXPECT_EMPTY();
+
+ // same as before but ending in path separator
+ TEST("dir1"PATH_SEPARATOR"dir1"PATH_SEPARATOR);
+ EXPECT_EMPTY();
+
+ // no glob - empty
+ TEST("empty");
+ EXPECT_EMPTY();
+
+ // same as before but ending in path separator
+ TEST("empty"PATH_SEPARATOR);
+ EXPECT_EMPTY();
+
+ // no glob - does not exist
+ TEST("not_exist");
+ EXPECT_EMPTY();
+
+#undef TEST
+#undef EXPECT
+#undef EXPECT_EMPTY
+
+ done:
+#ifndef _WIN32
+ {
+ int chmod_failed = 0;
+ if (forbidden)
+ chmod_failed |= chmod(forbidden, 0700);
+ if (dir1_forbidden)
+ chmod_failed |= chmod(dir1_forbidden, 0700);
+ if (dir2_forbidden)
+ chmod_failed |= chmod(dir2_forbidden, 0700);
+ if (forbidden_forbidden)
+ chmod_failed |= chmod(forbidden_forbidden, 0700);
+ if (chmod_failed) {
+ TT_FAIL(("unable to chmod a file on cleanup: %s", strerror(errno)));
+ }
+ }
+#endif
+ tor_free(dir1);
+ tor_free(dir2);
+ tor_free(forbidden);
+ tor_free(dirname);
+ tor_free(dir1_forbidden);
+ tor_free(dir2_forbidden);
+ tor_free(forbidden_forbidden);
+ tor_free(expected);
+ tor_free(pattern);
+ if (results) {
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f));
+ smartlist_free(results);
+ }
+#else
+ tt_skip();
+ done:
+ return;
+#endif
+}
+
+static void
test_util_parent_dir(void *ptr)
{
char *cp;
@@ -4368,204 +5014,6 @@ test_util_load_win_lib(void *ptr)
}
#endif /* defined(_WIN32) */
-#ifndef _WIN32
-static void
-clear_hex_errno(char *hex_errno)
-{
- memset(hex_errno, '\0', HEX_ERRNO_SIZE + 1);
-}
-
-static void
-test_util_exit_status(void *ptr)
-{
- /* Leave an extra byte for a \0 so we can do string comparison */
- char hex_errno[HEX_ERRNO_SIZE + 1];
- int n;
-
- (void)ptr;
-
- clear_hex_errno(hex_errno);
- tt_str_op("",OP_EQ, hex_errno);
-
- clear_hex_errno(hex_errno);
- n = format_helper_exit_status(0, 0, hex_errno);
- tt_str_op("0/0\n",OP_EQ, hex_errno);
- tt_int_op(n,OP_EQ, strlen(hex_errno));
-
-#if SIZEOF_INT == 4
-
- clear_hex_errno(hex_errno);
- n = format_helper_exit_status(0, 0x7FFFFFFF, hex_errno);
- tt_str_op("0/7FFFFFFF\n",OP_EQ, hex_errno);
- tt_int_op(n,OP_EQ, strlen(hex_errno));
-
- clear_hex_errno(hex_errno);
- n = format_helper_exit_status(0xFF, -0x80000000, hex_errno);
- tt_str_op("FF/-80000000\n",OP_EQ, hex_errno);
- tt_int_op(n,OP_EQ, strlen(hex_errno));
- tt_int_op(n,OP_EQ, HEX_ERRNO_SIZE);
-
-#elif SIZEOF_INT == 8
-
- clear_hex_errno(hex_errno);
- n = format_helper_exit_status(0, 0x7FFFFFFFFFFFFFFF, hex_errno);
- tt_str_op("0/7FFFFFFFFFFFFFFF\n",OP_EQ, hex_errno);
- tt_int_op(n,OP_EQ, strlen(hex_errno));
-
- clear_hex_errno(hex_errno);
- n = format_helper_exit_status(0xFF, -0x8000000000000000, hex_errno);
- tt_str_op("FF/-8000000000000000\n",OP_EQ, hex_errno);
- tt_int_op(n,OP_EQ, strlen(hex_errno));
- tt_int_op(n,OP_EQ, HEX_ERRNO_SIZE);
-
-#endif /* SIZEOF_INT == 4 || ... */
-
- clear_hex_errno(hex_errno);
- n = format_helper_exit_status(0x7F, 0, hex_errno);
- tt_str_op("7F/0\n",OP_EQ, hex_errno);
- tt_int_op(n,OP_EQ, strlen(hex_errno));
-
- clear_hex_errno(hex_errno);
- n = format_helper_exit_status(0x08, -0x242, hex_errno);
- tt_str_op("8/-242\n",OP_EQ, hex_errno);
- tt_int_op(n,OP_EQ, strlen(hex_errno));
-
- clear_hex_errno(hex_errno);
- tt_str_op("",OP_EQ, hex_errno);
-
- done:
- ;
-}
-#endif /* !defined(_WIN32) */
-
-#ifndef _WIN32
-static void
-test_util_string_from_pipe(void *ptr)
-{
- int test_pipe[2] = {-1, -1};
- int retval = 0;
- enum stream_status status = IO_STREAM_TERM;
- ssize_t retlen;
- char buf[4] = { 0 };
-
- (void)ptr;
-
- errno = 0;
-
- /* Set up a pipe to test on */
- retval = pipe(test_pipe);
- tt_int_op(retval, OP_EQ, 0);
-
- /* Send in a string. */
- retlen = write(test_pipe[1], "ABC", 3);
- tt_int_op(retlen, OP_EQ, 3);
-
- status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
- tt_int_op(errno, OP_EQ, 0);
- tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
- tt_str_op(buf, OP_EQ, "ABC");
- errno = 0;
-
- /* Send in a string that contains a nul. */
- retlen = write(test_pipe[1], "AB\0", 3);
- tt_int_op(retlen, OP_EQ, 3);
-
- status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
- tt_int_op(errno, OP_EQ, 0);
- tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
- tt_str_op(buf, OP_EQ, "AB");
- errno = 0;
-
- /* Send in a string that contains a nul only. */
- retlen = write(test_pipe[1], "\0", 1);
- tt_int_op(retlen, OP_EQ, 1);
-
- status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
- tt_int_op(errno, OP_EQ, 0);
- tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
- tt_str_op(buf, OP_EQ, "");
- errno = 0;
-
- /* Send in a string that contains a trailing newline. */
- retlen = write(test_pipe[1], "AB\n", 3);
- tt_int_op(retlen, OP_EQ, 3);
-
- status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
- tt_int_op(errno, OP_EQ, 0);
- tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
- tt_str_op(buf, OP_EQ, "AB");
- errno = 0;
-
- /* Send in a string that contains a newline only. */
- retlen = write(test_pipe[1], "\n", 1);
- tt_int_op(retlen, OP_EQ, 1);
-
- status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
- tt_int_op(errno, OP_EQ, 0);
- tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
- tt_str_op(buf, OP_EQ, "");
- errno = 0;
-
- /* Send in a string and check that we nul terminate return values. */
- retlen = write(test_pipe[1], "AAA", 3);
- tt_int_op(retlen, OP_EQ, 3);
-
- status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
- tt_int_op(errno, OP_EQ, 0);
- tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
- tt_str_op(buf, OP_EQ, "AAA");
- tt_mem_op(buf, OP_EQ, "AAA\0", sizeof(buf));
- errno = 0;
-
- retlen = write(test_pipe[1], "B", 1);
- tt_int_op(retlen, OP_EQ, 1);
-
- memset(buf, '\xff', sizeof(buf));
- status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
- tt_int_op(errno, OP_EQ, 0);
- tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
- tt_str_op(buf, OP_EQ, "B");
- tt_mem_op(buf, OP_EQ, "B\0\xff\xff", sizeof(buf));
- errno = 0;
-
- /* Send in multiple lines. */
- retlen = write(test_pipe[1], "A\nB", 3);
- tt_int_op(retlen, OP_EQ, 3);
-
- status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
- tt_int_op(errno, OP_EQ, 0);
- tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
- tt_str_op(buf, OP_EQ, "A\nB");
- errno = 0;
-
- /* Send in a line and close */
- retlen = write(test_pipe[1], "AB", 2);
- tt_int_op(retlen, OP_EQ, 2);
- retval = close(test_pipe[1]);
- tt_int_op(retval, OP_EQ, 0);
- test_pipe[1] = -1;
-
- status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
- tt_int_op(errno, OP_EQ, 0);
- tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
- tt_str_op(buf, OP_EQ, "AB");
- errno = 0;
-
- /* Check for EOF */
- status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
- tt_int_op(errno, OP_EQ, 0);
- tt_int_op(status, OP_EQ, IO_STREAM_CLOSED);
- errno = 0;
-
- done:
- if (test_pipe[0] != -1)
- close(test_pipe[0]);
- if (test_pipe[1] != -1)
- close(test_pipe[1]);
-}
-
-#endif /* !defined(_WIN32) */
-
/**
* Test for format_hex_number_sigsafe()
*/
@@ -4660,57 +5108,6 @@ test_util_format_dec_number(void *ptr)
return;
}
-/**
- * Test that we can properly format a Windows command line
- */
-static void
-test_util_join_win_cmdline(void *ptr)
-{
- /* Based on some test cases from "Parsing C++ Command-Line Arguments" in
- * MSDN but we don't exercise all quoting rules because tor_join_win_cmdline
- * will try to only generate simple cases for the child process to parse;
- * i.e. we never embed quoted strings in arguments. */
-
- const char *argvs[][4] = {
- {"a", "bb", "CCC", NULL}, // Normal
- {NULL, NULL, NULL, NULL}, // Empty argument list
- {"", NULL, NULL, NULL}, // Empty argument
- {"\"a", "b\"b", "CCC\"", NULL}, // Quotes
- {"a\tbc", "dd dd", "E", NULL}, // Whitespace
- {"a\\\\\\b", "de fg", "H", NULL}, // Backslashes
- {"a\\\"b", "\\c", "D\\", NULL}, // Backslashes before quote
- {"a\\\\b c", "d", "E", NULL}, // Backslashes not before quote
- { NULL } // Terminator
- };
-
- const char *cmdlines[] = {
- "a bb CCC",
- "",
- "\"\"",
- "\\\"a b\\\"b CCC\\\"",
- "\"a\tbc\" \"dd dd\" E",
- "a\\\\\\b \"de fg\" H",
- "a\\\\\\\"b \\c D\\",
- "\"a\\\\b c\" d E",
- NULL // Terminator
- };
-
- int i;
- char *joined_argv = NULL;
-
- (void)ptr;
-
- for (i=0; cmdlines[i]!=NULL; i++) {
- log_info(LD_GENERAL, "Joining argvs[%d], expecting <%s>", i, cmdlines[i]);
- joined_argv = tor_join_win_cmdline(argvs[i]);
- tt_str_op(cmdlines[i],OP_EQ, joined_argv);
- tor_free(joined_argv);
- }
-
- done:
- tor_free(joined_argv);
-}
-
#define MAX_SPLIT_LINE_COUNT 4
struct split_lines_test_t {
const char *orig_line; // Line to be split (may contain \0's)
@@ -4718,67 +5115,6 @@ struct split_lines_test_t {
const char *split_line[MAX_SPLIT_LINE_COUNT]; // Split lines
};
-/**
- * Test that we properly split a buffer into lines
- */
-static void
-test_util_split_lines(void *ptr)
-{
- /* Test cases. orig_line of last test case must be NULL.
- * The last element of split_line[i] must be NULL. */
- struct split_lines_test_t tests[] = {
- {"", 0, {NULL}},
- {"foo", 3, {"foo", NULL}},
- {"\n\rfoo\n\rbar\r\n", 12, {"foo", "bar", NULL}},
- {"fo o\r\nb\tar", 10, {"fo o", "b.ar", NULL}},
- {"\x0f""f\0o\0\n\x01""b\0r\0\r", 12, {".f.o.", ".b.r.", NULL}},
- {"line 1\r\nline 2", 14, {"line 1", "line 2", NULL}},
- {"line 1\r\n\r\nline 2", 16, {"line 1", "line 2", NULL}},
- {"line 1\r\n\r\r\r\nline 2", 18, {"line 1", "line 2", NULL}},
- {"line 1\r\n\n\n\n\rline 2", 18, {"line 1", "line 2", NULL}},
- {"line 1\r\n\r\t\r\nline 3", 18, {"line 1", ".", "line 3", NULL}},
- {"\n\t\r\t\nline 3", 11, {".", ".", "line 3", NULL}},
- {NULL, 0, { NULL }}
- };
-
- int i, j;
- char *orig_line=NULL;
- smartlist_t *sl=NULL;
-
- (void)ptr;
-
- for (i=0; tests[i].orig_line; i++) {
- sl = smartlist_new();
- /* Allocate space for string and trailing NULL */
- orig_line = tor_memdup(tests[i].orig_line, tests[i].orig_length + 1);
- tor_split_lines(sl, orig_line, tests[i].orig_length);
-
- j = 0;
- log_info(LD_GENERAL, "Splitting test %d of length %d",
- i, tests[i].orig_length);
- SMARTLIST_FOREACH_BEGIN(sl, const char *, line) {
- /* Check we have not got too many lines */
- tt_int_op(MAX_SPLIT_LINE_COUNT, OP_GT, j);
- /* Check that there actually should be a line here */
- tt_ptr_op(tests[i].split_line[j], OP_NE, NULL);
- log_info(LD_GENERAL, "Line %d of test %d, should be <%s>",
- j, i, tests[i].split_line[j]);
- /* Check that the line is as expected */
- tt_str_op(line,OP_EQ, tests[i].split_line[j]);
- j++;
- } SMARTLIST_FOREACH_END(line);
- /* Check that we didn't miss some lines */
- tt_ptr_op(NULL,OP_EQ, tests[i].split_line[j]);
- tor_free(orig_line);
- smartlist_free(sl);
- sl = NULL;
- }
-
- done:
- tor_free(orig_line);
- smartlist_free(sl);
-}
-
static void
test_util_di_ops(void *arg)
{
@@ -4865,6 +5201,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;
@@ -5730,6 +6095,13 @@ test_util_socketpair(void *arg)
tt_skip();
}
#endif /* defined(__FreeBSD__) */
+#ifdef ENETUNREACH
+ if (ersatz && socketpair_result == -ENETUNREACH) {
+ /* We can also fail with -ENETUNREACH if we have no network stack at
+ * all. */
+ tt_skip();
+ }
+#endif /* defined(ENETUNREACH) */
tt_int_op(0, OP_EQ, socketpair_result);
tt_assert(SOCKET_OK(fds[0]));
@@ -5843,7 +6215,7 @@ test_util_hostname_validation(void *arg)
// XXX: do we allow single-label DNS names?
// We shouldn't for SOCKS (spec says "contains a fully-qualified domain name"
- // but only test pathologically malformed traling '.' cases for now.
+ // but only test pathologically malformed trailing '.' cases for now.
tt_assert(!string_is_valid_nonrfc_hostname("."));
tt_assert(!string_is_valid_nonrfc_hostname(".."));
@@ -5858,7 +6230,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:
@@ -5882,6 +6254,18 @@ test_util_ipv4_validation(void *arg)
}
static void
+test_util_ipv6_validation(void *arg)
+{
+ (void)arg;
+
+ tt_assert(string_is_valid_ipv6_address("2a00:1450:401b:800::200e"));
+ tt_assert(!string_is_valid_ipv6_address("11:22::33:44:"));
+
+ done:
+ return;
+}
+
+static void
test_util_writepid(void *arg)
{
(void) arg;
@@ -5933,6 +6317,20 @@ test_util_get_avail_disk_space(void *arg)
;
}
+/** Helper: Change the atime and mtime of a file. */
+static void
+set_file_mtime(const char *fname, time_t when)
+{
+ struct utimbuf u = { when, when };
+ struct stat st;
+ tt_int_op(0, OP_EQ, utime(fname, &u));
+ tt_int_op(0, OP_EQ, stat(fname, &st));
+ /* Let's hope that utime/stat give the same second as a round-trip? */
+ tt_i64_op(st.st_mtime, OP_EQ, when);
+done:
+ ;
+}
+
static void
test_util_touch_file(void *arg)
{
@@ -5950,11 +6348,7 @@ test_util_touch_file(void *arg)
tt_i64_op(st.st_mtime, OP_GE, now - 1);
const time_t five_sec_ago = now - 5;
- struct utimbuf u = { five_sec_ago, five_sec_ago };
- tt_int_op(0, OP_EQ, utime(fname, &u));
- tt_int_op(0, OP_EQ, stat(fname, &st));
- /* Let's hope that utime/stat give the same second as a round-trip? */
- tt_i64_op(st.st_mtime, OP_EQ, five_sec_ago);
+ set_file_mtime(fname, five_sec_ago);
/* Finally we can touch the file */
tt_int_op(0, OP_EQ, touch_file(fname));
@@ -5965,7 +6359,7 @@ test_util_touch_file(void *arg)
;
}
-#ifndef _WIN32
+#ifndef DISABLE_PWDB_TESTS
static void
test_util_pwdb(void *arg)
{
@@ -6037,7 +6431,7 @@ test_util_pwdb(void *arg)
tor_free(dir);
teardown_capture_of_logs();
}
-#endif /* !defined(_WIN32) */
+#endif /* !defined(DISABLE_PWDB_TESTS) */
static void
test_util_calloc_check(void *arg)
@@ -6285,6 +6679,14 @@ test_util_nowrap_math(void *arg)
tt_u64_op(UINT32_MAX, OP_EQ, tor_add_u32_nowrap(2, UINT32_MAX-1));
tt_u64_op(UINT32_MAX, OP_EQ, tor_add_u32_nowrap(UINT32_MAX, UINT32_MAX));
+ tt_u64_op(0, OP_EQ, tor_mul_u64_nowrap(0, 0));
+ tt_u64_op(1, OP_EQ, tor_mul_u64_nowrap(1, 1));
+ tt_u64_op(2, OP_EQ, tor_mul_u64_nowrap(2, 1));
+ tt_u64_op(4, OP_EQ, tor_mul_u64_nowrap(2, 2));
+ tt_u64_op(UINT64_MAX, OP_EQ, tor_mul_u64_nowrap(UINT64_MAX, 1));
+ tt_u64_op(UINT64_MAX, OP_EQ, tor_mul_u64_nowrap(2, UINT64_MAX));
+ tt_u64_op(UINT64_MAX, OP_EQ, tor_mul_u64_nowrap(UINT64_MAX, UINT64_MAX));
+
done:
;
}
@@ -6394,40 +6796,168 @@ test_util_get_unquoted_path(void *arg)
tor_free(r);
}
+static void
+test_util_map_anon(void *arg)
+{
+ (void)arg;
+ char *ptr = NULL;
+ size_t sz = 16384;
+ unsigned inherit=0;
+
+ /* Basic checks. */
+ ptr = tor_mmap_anonymous(sz, 0, &inherit);
+ tt_ptr_op(ptr, OP_NE, 0);
+ tt_int_op(inherit, OP_EQ, INHERIT_RES_KEEP);
+ ptr[sz-1] = 3;
+ tt_int_op(ptr[0], OP_EQ, 0);
+ tt_int_op(ptr[sz-2], OP_EQ, 0);
+ tt_int_op(ptr[sz-1], OP_EQ, 3);
+
+ /* Try again, with a private (non-swappable) mapping. */
+ tor_munmap_anonymous(ptr, sz);
+ ptr = tor_mmap_anonymous(sz, ANONMAP_PRIVATE, &inherit);
+ tt_ptr_op(ptr, OP_NE, 0);
+ tt_int_op(inherit, OP_EQ, INHERIT_RES_KEEP);
+ ptr[sz-1] = 10;
+ tt_int_op(ptr[0], OP_EQ, 0);
+ tt_int_op(ptr[sz/2], OP_EQ, 0);
+ tt_int_op(ptr[sz-1], OP_EQ, 10);
+
+ /* Now let's test a drop-on-fork mapping. */
+ tor_munmap_anonymous(ptr, sz);
+ ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT, &inherit);
+ tt_ptr_op(ptr, OP_NE, 0);
+ ptr[sz-1] = 10;
+ tt_int_op(ptr[0], OP_EQ, 0);
+ tt_int_op(ptr[sz/2], OP_EQ, 0);
+ tt_int_op(ptr[sz-1], OP_EQ, 10);
+
+ done:
+ tor_munmap_anonymous(ptr, sz);
+}
+
+static void
+test_util_map_anon_nofork(void *arg)
+{
+ (void)arg;
+#ifdef _WIN32
+ /* The operating system doesn't support forking. */
+ tt_skip();
+ done:
+ ;
+#else /* !defined(_WIN32) */
+ /* We have the right OS support. We're going to try marking the buffer as
+ * either zero-on-fork or as drop-on-fork, whichever is supported. Then we
+ * will fork and send a byte back to the parent process. This will either
+ * crash, or send zero. */
+
+ char *ptr = NULL;
+ const char TEST_VALUE = 0xd0;
+ size_t sz = 16384;
+ int pipefd[2] = {-1, -1};
+ unsigned inherit=0;
+
+ tor_munmap_anonymous(ptr, sz);
+ ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT, &inherit);
+ tt_ptr_op(ptr, OP_NE, 0);
+ memset(ptr, (uint8_t)TEST_VALUE, sz);
+
+ tt_int_op(0, OP_EQ, pipe(pipefd));
+ pid_t child = fork();
+ if (child == 0) {
+ /* We're in the child. */
+ close(pipefd[0]);
+ ssize_t r = write(pipefd[1], &ptr[sz-1], 1); /* This may crash. */
+ close(pipefd[1]);
+ if (r < 0)
+ exit(1);
+ exit(0);
+ }
+ tt_int_op(child, OP_GT, 0);
+ /* In the parent. */
+ close(pipefd[1]);
+ pipefd[1] = -1;
+ char buf[1];
+ ssize_t r = read(pipefd[0], buf, 1);
+
+ if (inherit == INHERIT_RES_ZERO) {
+ // We should be seeing clear-on-fork behavior.
+ tt_int_op((int)r, OP_EQ, 1); // child should send us a byte.
+ tt_int_op(buf[0], OP_EQ, 0); // that byte should be zero.
+ } else if (inherit == INHERIT_RES_DROP) {
+ // We should be seeing noinherit behavior.
+ tt_int_op(r, OP_LE, 0); // child said nothing; it should have crashed.
+ } else {
+ // noinherit isn't implemented.
+ tt_int_op(inherit, OP_EQ, INHERIT_RES_KEEP);
+ tt_int_op((int)r, OP_EQ, 1); // child should send us a byte.
+ tt_int_op(buf[0], OP_EQ, TEST_VALUE); // that byte should be TEST_VALUE.
+ }
+
+ int ws;
+ waitpid(child, &ws, 0);
+
+#ifndef NOINHERIT_CAN_FAIL
+ /* Only if NOINHERIT_CAN_FAIL should it be possible for us to get
+ * INHERIT_KEEP behavior in this case. */
+ tt_int_op(inherit, OP_NE, INHERIT_RES_KEEP);
+#else
+ if (inherit == INHERIT_RES_KEEP) {
+ /* Call this test "skipped", not "passed", since noinherit wasn't
+ * implemented. */
+ tt_skip();
+ }
+#endif /* !defined(NOINHERIT_CAN_FAIL) */
+
+ done:
+ tor_munmap_anonymous(ptr, sz);
+ if (pipefd[0] >= 0) {
+ close(pipefd[0]);
+ }
+ if (pipefd[1] >= 0) {
+ close(pipefd[1]);
+ }
+#endif /* defined(_WIN32) */
+}
+
+#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) }
#ifdef _WIN32
-#define UTIL_TEST_NO_WIN(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
#define UTIL_TEST_WIN_ONLY(n, f) UTIL_TEST(n, (f))
-#define UTIL_LEGACY_NO_WIN(n) UTIL_TEST_NO_WIN(n, 0)
#else
-#define UTIL_TEST_NO_WIN(n, f) UTIL_TEST(n, (f))
-#define UTIL_TEST_WIN_ONLY(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
-#define UTIL_LEGACY_NO_WIN(n) UTIL_LEGACY(n)
-#endif /* defined(_WIN32) */
+#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 }
+#else
+#define UTIL_TEST_PWDB(n, f) UTIL_TEST(n, (f))
+#endif
+#endif /* !defined(COCCI) */
struct testcase_t util_tests[] = {
UTIL_LEGACY(time),
@@ -6437,7 +6967,8 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(config_line_comment_character),
UTIL_LEGACY(config_line_escaped_content),
UTIL_LEGACY(config_line_crlf),
- UTIL_LEGACY_NO_WIN(expand_filename),
+ UTIL_TEST(config_line_partition, 0),
+ UTIL_TEST_PWDB(expand_filename, 0),
UTIL_LEGACY(escape_string_socks),
UTIL_LEGACY(string_is_key_value),
UTIL_LEGACY(strmisc),
@@ -6473,26 +7004,26 @@ 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),
UTIL_TEST(clamp_double_to_int64, 0),
UTIL_TEST(find_str_at_start_of_line, 0),
+ UTIL_TEST(tor_strreplacechar, 0),
UTIL_TEST(string_is_C_identifier, 0),
UTIL_TEST(string_is_utf8, 0),
UTIL_TEST(asprintf, 0),
UTIL_TEST(listdir, 0),
+ UTIL_TEST(glob, 0),
+ UTIL_TEST(get_glob_opened_files, 0),
UTIL_TEST(parent_dir, 0),
UTIL_TEST(ftruncate, 0),
UTIL_TEST(nowrap_math, 0),
UTIL_TEST(num_cpus, 0),
UTIL_TEST_WIN_ONLY(load_win_lib, 0),
- UTIL_TEST_NO_WIN(exit_status, 0),
- UTIL_TEST_NO_WIN(string_from_pipe, 0),
UTIL_TEST(format_hex_number, 0),
UTIL_TEST(format_dec_number, 0),
- UTIL_TEST(join_win_cmdline, 0),
- UTIL_TEST(split_lines, 0),
UTIL_TEST(n_bits_set, 0),
UTIL_TEST(eat_whitespace, 0),
UTIL_TEST(sl_new_from_text_lines, 0),
@@ -6507,9 +7038,11 @@ struct testcase_t util_tests[] = {
UTIL_TEST(read_file_eof_zero_bytes, 0),
UTIL_TEST(read_file_endlines, 0),
UTIL_TEST(write_chunks_to_file, 0),
+ UTIL_TEST(write_str_if_changed, 0),
UTIL_TEST(mathlog, 0),
UTIL_TEST(fraction, 0),
UTIL_TEST(weak_random, 0),
+ { "tor_isinf", test_tor_isinf, TT_FORK, NULL, NULL },
{ "socket_ipv4", test_util_socket, TT_FORK, &passthrough_setup,
(void*)"4" },
{ "socket_ipv6", test_util_socket, TT_FORK,
@@ -6522,16 +7055,20 @@ struct testcase_t util_tests[] = {
UTIL_TEST(hostname_validation, 0),
UTIL_TEST(dest_validation_edgecase, 0),
UTIL_TEST(ipv4_validation, 0),
+ UTIL_TEST(ipv6_validation, 0),
UTIL_TEST(writepid, 0),
UTIL_TEST(get_avail_disk_space, 0),
UTIL_TEST(touch_file, 0),
- UTIL_TEST_NO_WIN(pwdb, TT_FORK),
+ UTIL_TEST_PWDB(pwdb, TT_FORK),
UTIL_TEST(calloc_check, 0),
UTIL_TEST(monotonic_time, 0),
UTIL_TEST(monotonic_time_ratchet, TT_FORK),
UTIL_TEST(monotonic_time_zero, 0),
UTIL_TEST(monotonic_time_add_msec, 0),
+ UTIL_TEST(timegm_real, 0),
UTIL_TEST(htonll, 0),
UTIL_TEST(get_unquoted_path, 0),
+ UTIL_TEST(map_anon, 0),
+ UTIL_TEST(map_anon_nofork, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c
index d344d0e95c..726e8e7427 100644
--- a/src/test/test_util_format.c
+++ b/src/test/test_util_format.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -7,11 +7,8 @@
#include "test/test.h"
#include "lib/crypt_ops/crypto_rand.h"
-#define UTIL_FORMAT_PRIVATE
#include "lib/encoding/binascii.h"
-#define NS_MODULE util_format
-
static void
test_util_format_unaligned_accessors(void *ignored)
{
@@ -346,7 +343,7 @@ test_util_format_base32_decode(void *arg)
const char *src = "mjwgc2dcnrswqmjs";
ret = base32_decode(dst, strlen(expected), src, strlen(src));
- tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(ret, OP_EQ, 10);
tt_str_op(expected, OP_EQ, dst);
}
@@ -357,7 +354,7 @@ test_util_format_base32_decode(void *arg)
const char *src = "mjwgc2dcnrswq";
ret = base32_decode(dst, strlen(expected), src, strlen(src));
- tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(ret, OP_EQ, 8);
tt_mem_op(expected, OP_EQ, dst, strlen(expected));
}
@@ -367,7 +364,7 @@ test_util_format_base32_decode(void *arg)
ret = base32_decode(dst, real_dstlen, "#abcde", 6);
tt_int_op(ret, OP_EQ, -1);
/* Make sure the destination buffer has been zeroed even on error. */
- tt_int_op(tor_mem_is_zero(dst, real_dstlen), OP_EQ, 1);
+ tt_int_op(fast_mem_is_zero(dst, real_dstlen), OP_EQ, 1);
}
done:
@@ -392,10 +389,13 @@ test_util_format_encoded_size(void *arg)
base64_encode(outbuf, sizeof(outbuf), (char *)inbuf, i, 0);
tt_int_op(strlen(outbuf), OP_EQ, base64_encode_size(i, 0));
+ tt_int_op(i, OP_LE, base64_decode_maxsize(strlen(outbuf)));
+
base64_encode(outbuf, sizeof(outbuf), (char *)inbuf, i,
BASE64_ENCODE_MULTILINE);
tt_int_op(strlen(outbuf), OP_EQ,
base64_encode_size(i, BASE64_ENCODE_MULTILINE));
+ tt_int_op(i, OP_LE, base64_decode_maxsize(strlen(outbuf)));
}
done:
@@ -417,4 +417,3 @@ struct testcase_t util_format_tests[] = {
{ "encoded_size", test_util_format_encoded_size, 0, NULL, NULL },
END_OF_TESTCASES
};
-
diff --git a/src/test/test_util_process.c b/src/test/test_util_process.c
index 4d04eb6dfc..fc79fe9b1f 100644
--- a/src/test/test_util_process.c
+++ b/src/test/test_util_process.c
@@ -1,7 +1,6 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define UTIL_PROCESS_PRIVATE
#include "orconfig.h"
#include "core/or/or.h"
@@ -12,7 +11,6 @@
#include "test/log_test_helpers.h"
#ifndef _WIN32
-#define NS_MODULE util_process
static void
temp_callback(int r, void *s)
@@ -69,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_util_slow.c b/src/test/test_util_slow.c
deleted file mode 100644
index 29e30eaa11..0000000000
--- a/src/test/test_util_slow.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/* Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-#include "orconfig.h"
-#define UTIL_PRIVATE
-#define SUBPROCESS_PRIVATE
-#include "lib/crypt_ops/crypto_cipher.h"
-#include "lib/log/log.h"
-#include "lib/process/subprocess.h"
-#include "lib/process/waitpid.h"
-#include "lib/string/printf.h"
-#include "lib/time/compat_time.h"
-#include "test/test.h"
-
-#include <errno.h>
-#include <string.h>
-
-#ifndef BUILDDIR
-#define BUILDDIR "."
-#endif
-
-#ifdef _WIN32
-#define notify_pending_waitpid_callbacks() STMT_NIL
-#define TEST_CHILD "test-child.exe"
-#define EOL "\r\n"
-#else
-#define TEST_CHILD (BUILDDIR "/src/test/test-child")
-#define EOL "\n"
-#endif /* defined(_WIN32) */
-
-#ifdef _WIN32
-/* I've assumed Windows doesn't have the gap between fork and exec
- * that causes the race condition on unix-like platforms */
-#define MATCH_PROCESS_STATUS(s1,s2) ((s1) == (s2))
-
-#else /* !(defined(_WIN32)) */
-/* work around a race condition of the timing of SIGCHLD handler updates
- * to the process_handle's fields, and checks of those fields
- *
- * TODO: Once we can signal failure to exec, change PROCESS_STATUS_RUNNING to
- * PROCESS_STATUS_ERROR (and similarly with *_OR_NOTRUNNING) */
-#define PROCESS_STATUS_RUNNING_OR_NOTRUNNING (PROCESS_STATUS_RUNNING+1)
-#define IS_RUNNING_OR_NOTRUNNING(s) \
- ((s) == PROCESS_STATUS_RUNNING || (s) == PROCESS_STATUS_NOTRUNNING)
-/* well, this is ugly */
-#define MATCH_PROCESS_STATUS(s1,s2) \
- ( (s1) == (s2) \
- ||((s1) == PROCESS_STATUS_RUNNING_OR_NOTRUNNING \
- && IS_RUNNING_OR_NOTRUNNING(s2)) \
- ||((s2) == PROCESS_STATUS_RUNNING_OR_NOTRUNNING \
- && IS_RUNNING_OR_NOTRUNNING(s1)))
-
-#endif /* defined(_WIN32) */
-
-/** Helper function for testing tor_spawn_background */
-static void
-run_util_spawn_background(const char *argv[], const char *expected_out,
- const char *expected_err, int expected_exit,
- int expected_status)
-{
- int retval, exit_code;
- ssize_t pos;
- process_handle_t *process_handle=NULL;
- char stdout_buf[100], stderr_buf[100];
- int status;
-
- /* Start the program */
-#ifdef _WIN32
- status = tor_spawn_background(NULL, argv, NULL, &process_handle);
-#else
- status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
-#endif
-
- notify_pending_waitpid_callbacks();
-
- /* the race condition doesn't affect status,
- * because status isn't updated by the SIGCHLD handler,
- * but we still need to handle PROCESS_STATUS_RUNNING_OR_NOTRUNNING */
- tt_assert(MATCH_PROCESS_STATUS(expected_status, status));
- if (status == PROCESS_STATUS_ERROR) {
- tt_ptr_op(process_handle, OP_EQ, NULL);
- return;
- }
-
- tt_ptr_op(process_handle, OP_NE, NULL);
-
- /* When a spawned process forks, fails, then exits very quickly,
- * (this typically occurs when exec fails)
- * there is a race condition between the SIGCHLD handler
- * updating the process_handle's fields, and this test
- * checking the process status in those fields.
- * The SIGCHLD update can occur before or after the code below executes.
- * This causes intermittent failures in spawn_background_fail(),
- * typically when the machine is under load.
- * We use PROCESS_STATUS_RUNNING_OR_NOTRUNNING to avoid this issue. */
-
- /* the race condition affects the change in
- * process_handle->status from RUNNING to NOTRUNNING */
- tt_assert(MATCH_PROCESS_STATUS(expected_status, process_handle->status));
-
-#ifndef _WIN32
- notify_pending_waitpid_callbacks();
- /* the race condition affects the change in
- * process_handle->waitpid_cb to NULL,
- * so we skip the check if expected_status is ambiguous,
- * that is, PROCESS_STATUS_RUNNING_OR_NOTRUNNING */
- tt_assert(process_handle->waitpid_cb != NULL
- || expected_status == PROCESS_STATUS_RUNNING_OR_NOTRUNNING);
-#endif /* !defined(_WIN32) */
-
-#ifdef _WIN32
- tt_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE);
- tt_assert(process_handle->stderr_pipe != INVALID_HANDLE_VALUE);
- tt_assert(process_handle->stdin_pipe != INVALID_HANDLE_VALUE);
-#else
- tt_assert(process_handle->stdout_pipe >= 0);
- tt_assert(process_handle->stderr_pipe >= 0);
- tt_assert(process_handle->stdin_pipe >= 0);
-#endif /* defined(_WIN32) */
-
- /* Check stdout */
- pos = tor_read_all_from_process_stdout(process_handle, stdout_buf,
- sizeof(stdout_buf) - 1);
- tt_assert(pos >= 0);
- stdout_buf[pos] = '\0';
- tt_int_op(strlen(expected_out),OP_EQ, pos);
- tt_str_op(expected_out,OP_EQ, stdout_buf);
-
- notify_pending_waitpid_callbacks();
-
- /* Check it terminated correctly */
- retval = tor_get_exit_code(process_handle, 1, &exit_code);
- tt_int_op(PROCESS_EXIT_EXITED,OP_EQ, retval);
- tt_int_op(expected_exit,OP_EQ, exit_code);
- // TODO: Make test-child exit with something other than 0
-
-#ifndef _WIN32
- notify_pending_waitpid_callbacks();
- tt_ptr_op(process_handle->waitpid_cb, OP_EQ, NULL);
-#endif
-
- /* Check stderr */
- pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
- sizeof(stderr_buf) - 1);
- tt_assert(pos >= 0);
- stderr_buf[pos] = '\0';
- tt_str_op(expected_err,OP_EQ, stderr_buf);
- tt_int_op(strlen(expected_err),OP_EQ, pos);
-
- notify_pending_waitpid_callbacks();
-
- done:
- if (process_handle)
- tor_process_handle_destroy(process_handle, 1);
-}
-
-/** Check that we can launch a process and read the output */
-static void
-test_util_spawn_background_ok(void *ptr)
-{
- const char *argv[] = {TEST_CHILD, "--test", NULL};
- const char *expected_out = "OUT"EOL "--test"EOL "SLEEPING"EOL "DONE" EOL;
- const char *expected_err = "ERR"EOL;
-
- (void)ptr;
-
- run_util_spawn_background(argv, expected_out, expected_err, 0,
- PROCESS_STATUS_RUNNING);
-}
-
-/** Check that failing to find the executable works as expected */
-static void
-test_util_spawn_background_fail(void *ptr)
-{
- const char *argv[] = {BUILDDIR "/src/test/no-such-file", "--test", NULL};
- const char *expected_err = "";
- char expected_out[1024];
- char code[32];
-#ifdef _WIN32
- const int expected_status = PROCESS_STATUS_ERROR;
-#else
- /* TODO: Once we can signal failure to exec, set this to be
- * PROCESS_STATUS_RUNNING_OR_ERROR */
- const int expected_status = PROCESS_STATUS_RUNNING_OR_NOTRUNNING;
-#endif /* defined(_WIN32) */
-
- memset(expected_out, 0xf0, sizeof(expected_out));
- memset(code, 0xf0, sizeof(code));
-
- (void)ptr;
-
- tor_snprintf(code, sizeof(code), "%x/%x",
- 9 /* CHILD_STATE_FAILEXEC */ , ENOENT);
- tor_snprintf(expected_out, sizeof(expected_out),
- "ERR: Failed to spawn background process - code %s\n", code);
-
- run_util_spawn_background(argv, expected_out, expected_err, 255,
- expected_status);
-}
-
-/** Test that reading from a handle returns a partial read rather than
- * blocking */
-static void
-test_util_spawn_background_partial_read_impl(int exit_early)
-{
- const int expected_exit = 0;
- const int expected_status = PROCESS_STATUS_RUNNING;
-
- int retval, exit_code;
- ssize_t pos = -1;
- process_handle_t *process_handle=NULL;
- int status;
- char stdout_buf[100], stderr_buf[100];
-
- const char *argv[] = {TEST_CHILD, "--test", NULL};
- const char *expected_out[] = { "OUT" EOL "--test" EOL "SLEEPING" EOL,
- "DONE" EOL,
- NULL };
- const char *expected_err = "ERR" EOL;
-
-#ifndef _WIN32
- int eof = 0;
-#endif
- int expected_out_ctr;
-
- if (exit_early) {
- argv[1] = "--hang";
- expected_out[0] = "OUT"EOL "--hang"EOL "SLEEPING" EOL;
- }
-
- /* Start the program */
-#ifdef _WIN32
- status = tor_spawn_background(NULL, argv, NULL, &process_handle);
-#else
- status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
-#endif
- tt_int_op(expected_status,OP_EQ, status);
- tt_assert(process_handle);
- tt_int_op(expected_status,OP_EQ, process_handle->status);
-
- /* Check stdout */
- for (expected_out_ctr = 0; expected_out[expected_out_ctr] != NULL;) {
-#ifdef _WIN32
- pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
- sizeof(stdout_buf) - 1, NULL);
-#else
- /* Check that we didn't read the end of file last time */
- tt_assert(!eof);
- pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
- sizeof(stdout_buf) - 1, NULL, &eof);
-#endif /* defined(_WIN32) */
- log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos);
-
- /* We would have blocked, keep on trying */
- if (0 == pos)
- continue;
-
- tt_assert(pos > 0);
- stdout_buf[pos] = '\0';
- tt_str_op(expected_out[expected_out_ctr],OP_EQ, stdout_buf);
- tt_int_op(strlen(expected_out[expected_out_ctr]),OP_EQ, pos);
- expected_out_ctr++;
- }
-
- if (exit_early) {
- tor_process_handle_destroy(process_handle, 1);
- process_handle = NULL;
- goto done;
- }
-
- /* The process should have exited without writing more */
-#ifdef _WIN32
- pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
- sizeof(stdout_buf) - 1,
- process_handle);
- tt_int_op(0,OP_EQ, pos);
-#else /* !(defined(_WIN32)) */
- if (!eof) {
- /* We should have got all the data, but maybe not the EOF flag */
- pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
- sizeof(stdout_buf) - 1,
- process_handle, &eof);
- tt_int_op(0,OP_EQ, pos);
- tt_assert(eof);
- }
- /* Otherwise, we got the EOF on the last read */
-#endif /* defined(_WIN32) */
-
- /* Check it terminated correctly */
- retval = tor_get_exit_code(process_handle, 1, &exit_code);
- tt_int_op(PROCESS_EXIT_EXITED,OP_EQ, retval);
- tt_int_op(expected_exit,OP_EQ, exit_code);
-
- // TODO: Make test-child exit with something other than 0
-
- /* Check stderr */
- pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
- sizeof(stderr_buf) - 1);
- tt_assert(pos >= 0);
- stderr_buf[pos] = '\0';
- tt_str_op(expected_err,OP_EQ, stderr_buf);
- tt_int_op(strlen(expected_err),OP_EQ, pos);
-
- done:
- tor_process_handle_destroy(process_handle, 1);
-}
-
-static void
-test_util_spawn_background_partial_read(void *arg)
-{
- (void)arg;
- test_util_spawn_background_partial_read_impl(0);
-}
-
-static void
-test_util_spawn_background_exit_early(void *arg)
-{
- (void)arg;
- test_util_spawn_background_partial_read_impl(1);
-}
-
-static void
-test_util_spawn_background_waitpid_notify(void *arg)
-{
- int retval, exit_code;
- process_handle_t *process_handle=NULL;
- int status;
- int ms_timer;
-
- const char *argv[] = {TEST_CHILD, "--fast", NULL};
-
- (void) arg;
-
-#ifdef _WIN32
- status = tor_spawn_background(NULL, argv, NULL, &process_handle);
-#else
- status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
-#endif
-
- tt_int_op(status, OP_EQ, PROCESS_STATUS_RUNNING);
- tt_ptr_op(process_handle, OP_NE, NULL);
-
- /* We're not going to look at the stdout/stderr output this time. Instead,
- * we're testing whether notify_pending_waitpid_calbacks() can report the
- * process exit (on unix) and/or whether tor_get_exit_code() can notice it
- * (on windows) */
-
-#ifndef _WIN32
- ms_timer = 30*1000;
- tt_ptr_op(process_handle->waitpid_cb, OP_NE, NULL);
- while (process_handle->waitpid_cb && ms_timer > 0) {
- tor_sleep_msec(100);
- ms_timer -= 100;
- notify_pending_waitpid_callbacks();
- }
- tt_int_op(ms_timer, OP_GT, 0);
- tt_ptr_op(process_handle->waitpid_cb, OP_EQ, NULL);
-#endif /* !defined(_WIN32) */
-
- ms_timer = 30*1000;
- while (((retval = tor_get_exit_code(process_handle, 0, &exit_code))
- == PROCESS_EXIT_RUNNING) && ms_timer > 0) {
- tor_sleep_msec(100);
- ms_timer -= 100;
- }
- tt_int_op(ms_timer, OP_GT, 0);
-
- tt_int_op(retval, OP_EQ, PROCESS_EXIT_EXITED);
-
- done:
- tor_process_handle_destroy(process_handle, 1);
-}
-
-#undef TEST_CHILD
-#undef EOL
-
-#undef MATCH_PROCESS_STATUS
-
-#ifndef _WIN32
-#undef PROCESS_STATUS_RUNNING_OR_NOTRUNNING
-#undef IS_RUNNING_OR_NOTRUNNING
-#endif
-
-#define UTIL_TEST(name, flags) \
- { #name, test_util_ ## name, flags, NULL, NULL }
-
-struct testcase_t slow_util_tests[] = {
- UTIL_TEST(spawn_background_ok, 0),
- UTIL_TEST(spawn_background_fail, 0),
- UTIL_TEST(spawn_background_partial_read, 0),
- UTIL_TEST(spawn_background_exit_early, 0),
- UTIL_TEST(spawn_background_waitpid_notify, 0),
- END_OF_TESTCASES
-};
diff --git a/src/test/test_voting_flags.c b/src/test/test_voting_flags.c
new file mode 100644
index 0000000000..72f70b9865
--- /dev/null
+++ b/src/test/test_voting_flags.c
@@ -0,0 +1,193 @@
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define VOTEFLAGS_PRIVATE
+
+#include "core/or/or.h"
+
+#include "feature/dirauth/voteflags.h"
+#include "feature/dirauth/dirauth_options_st.h"
+#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/routerstatus_st.h"
+#include "feature/nodelist/routerinfo_st.h"
+
+#include "app/config/config.h"
+
+#include "test/test.h"
+#include "test/opts_test_helpers.h"
+
+typedef struct {
+ time_t now;
+ routerinfo_t ri;
+ node_t node;
+
+ routerstatus_t expected;
+} flag_vote_test_cfg_t;
+
+static void
+setup_cfg(flag_vote_test_cfg_t *c)
+{
+ memset(c, 0, sizeof(*c));
+
+ c->now = approx_time();
+
+ c->ri.nickname = (char *) "testing100";
+ strlcpy(c->expected.nickname, "testing100", sizeof(c->expected.nickname));
+
+ memset(c->ri.cache_info.identity_digest, 0xff, DIGEST_LEN);
+ memset(c->ri.cache_info.signed_descriptor_digest, 0xee, DIGEST_LEN);
+
+ c->ri.cache_info.published_on = c->now - 100;
+ c->expected.published_on = c->now - 100;
+
+ tor_addr_from_ipv4h(&c->ri.ipv4_addr, 0x7f010105);
+ tor_addr_from_ipv4h(&c->expected.ipv4_addr, 0x7f010105);
+ c->ri.ipv4_orport = 9090;
+ c->expected.ipv4_orport = 9090;
+
+ tor_addr_make_null(&c->ri.ipv6_addr, AF_INET6);
+ tor_addr_make_null(&c->expected.ipv6_addr, AF_INET6);
+
+ // By default we have no loaded information about stability or speed,
+ // so we'll default to voting "yeah sure." on these two.
+ c->expected.is_fast = 1;
+ c->expected.is_stable = 1;
+}
+
+static bool
+check_result(flag_vote_test_cfg_t *c)
+{
+ bool result = false;
+ routerstatus_t rs;
+ memset(&rs, 0, sizeof(rs));
+ dirauth_set_routerstatus_from_routerinfo(&rs, &c->node, &c->ri, c->now, 0);
+
+ tt_i64_op(rs.published_on, OP_EQ, c->expected.published_on);
+ tt_str_op(rs.nickname, OP_EQ, c->expected.nickname);
+
+ // identity_digest and descriptor_digest are not set here.
+
+ tt_assert(tor_addr_eq(&rs.ipv4_addr, &c->expected.ipv4_addr));
+ tt_uint_op(rs.ipv4_orport, OP_EQ, c->expected.ipv4_orport);
+ tt_uint_op(rs.ipv4_dirport, OP_EQ, c->expected.ipv4_dirport);
+
+ tt_assert(tor_addr_eq(&rs.ipv6_addr, &c->expected.ipv6_addr));
+ tt_uint_op(rs.ipv6_orport, OP_EQ, c->expected.ipv6_orport);
+
+#define FLAG(flagname) \
+ tt_uint_op(rs.flagname, OP_EQ, c->expected.flagname)
+
+ FLAG(is_authority);
+ FLAG(is_exit);
+ FLAG(is_stable);
+ FLAG(is_fast);
+ FLAG(is_flagged_running);
+ FLAG(is_named);
+ FLAG(is_unnamed);
+ FLAG(is_valid);
+ FLAG(is_possible_guard);
+ FLAG(is_bad_exit);
+ FLAG(is_hs_dir);
+ FLAG(is_v2_dir);
+ FLAG(is_staledesc);
+ FLAG(has_bandwidth);
+ FLAG(has_exitsummary);
+ FLAG(bw_is_unmeasured);
+
+ result = true;
+
+ done:
+ return result;
+}
+
+static void
+test_voting_flags_minimal(void *arg)
+{
+ flag_vote_test_cfg_t *cfg = arg;
+ (void) check_result(cfg);
+}
+
+static void
+test_voting_flags_ipv6(void *arg)
+{
+ flag_vote_test_cfg_t *cfg = arg;
+
+ tt_assert(tor_addr_parse(&cfg->ri.ipv6_addr, "f00::b42") == AF_INET6);
+ cfg->ri.ipv6_orport = 9091;
+ // no change in expected results, since we aren't set up with ipv6
+ // connectivity.
+ if (!check_result(cfg))
+ goto done;
+
+ get_dirauth_options(get_options_mutable())->AuthDirHasIPv6Connectivity = 1;
+ // no change in expected results, since last_reachable6 won't be set.
+ if (!check_result(cfg))
+ goto done;
+
+ cfg->node.last_reachable6 = cfg->now - 10;
+ // now that lastreachable6 is set, we expect to see the result.
+ tt_assert(tor_addr_parse(&cfg->expected.ipv6_addr, "f00::b42") == AF_INET6);
+ cfg->expected.ipv6_orport = 9091;
+ if (!check_result(cfg))
+ goto done;
+ done:
+ ;
+}
+
+static void
+test_voting_flags_staledesc(void *arg)
+{
+ flag_vote_test_cfg_t *cfg = arg;
+ time_t now = cfg->now;
+
+ cfg->ri.cache_info.published_on = now - DESC_IS_STALE_INTERVAL + 10;
+ cfg->expected.published_on = now - DESC_IS_STALE_INTERVAL + 10;
+ // no change in expectations for is_staledesc
+ if (!check_result(cfg))
+ goto done;
+
+ cfg->ri.cache_info.published_on = now - DESC_IS_STALE_INTERVAL - 10;
+ cfg->expected.published_on = now - DESC_IS_STALE_INTERVAL - 10;
+ cfg->expected.is_staledesc = 1;
+ if (!check_result(cfg))
+ goto done;
+
+ done:
+ ;
+}
+
+static void *
+setup_voting_flags_test(const struct testcase_t *testcase)
+{
+ (void)testcase;
+ flag_vote_test_cfg_t *cfg = tor_malloc_zero(sizeof(*cfg));
+ setup_cfg(cfg);
+ return cfg;
+}
+
+static int
+teardown_voting_flags_test(const struct testcase_t *testcase, void *arg)
+{
+ (void)testcase;
+ flag_vote_test_cfg_t *cfg = arg;
+ tor_free(cfg);
+ return 1;
+}
+
+static const struct testcase_setup_t voting_flags_setup = {
+ .setup_fn = setup_voting_flags_test,
+ .cleanup_fn = teardown_voting_flags_test,
+};
+
+#define T(name,flags) \
+ { #name, test_voting_flags_##name, (flags), &voting_flags_setup, NULL }
+
+struct testcase_t voting_flags_tests[] = {
+ T(minimal, 0),
+ T(ipv6, TT_FORK),
+ // TODO: Add more of these tests.
+ T(staledesc, TT_FORK),
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_voting_schedule.c b/src/test/test_voting_schedule.c
index ba4d53a4ae..df64b79167 100644
--- a/src/test/test_voting_schedule.c
+++ b/src/test/test_voting_schedule.c
@@ -1,17 +1,18 @@
-/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* Copyright (c) 2018-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#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/test_workqueue.c b/src/test/test_workqueue.c
index c58634da5c..3734c08e48 100644
--- a/src/test/test_workqueue.c
+++ b/src/test/test_workqueue.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
@@ -32,7 +32,7 @@ int handled_len;
bitarray_t *handled;
#endif
-typedef struct state_s {
+typedef struct state_t {
int magic;
int n_handled;
crypto_pk_t *rsa;
@@ -40,13 +40,13 @@ typedef struct state_s {
int is_shutdown;
} state_t;
-typedef struct rsa_work_s {
+typedef struct rsa_work_t {
int serial;
uint8_t msg[128];
uint8_t msglen;
} rsa_work_t;
-typedef struct ecdh_work_s {
+typedef struct ecdh_work_t {
int serial;
union {
curve25519_public_key_t pk;
@@ -63,7 +63,7 @@ mark_handled(int serial)
tor_assert(! bitarray_is_set(handled, serial));
bitarray_set(handled, serial);
tor_mutex_release(&bitmap_mutex);
-#else /* !(defined(TRACK_RESPONSES)) */
+#else /* !defined(TRACK_RESPONSES) */
(void)serial;
#endif /* defined(TRACK_RESPONSES) */
}
@@ -339,7 +339,7 @@ main(int argc, char **argv)
replyqueue_t *rq;
threadpool_t *tp;
int i;
- tor_libevent_cfg evcfg;
+ tor_libevent_cfg_t evcfg;
uint32_t as_flags = 0;
for (i = 1; i < argc; ++i) {
diff --git a/src/test/test_workqueue_cancel.sh b/src/test/test_workqueue_cancel.sh
index f7c663171e..e50b884f26 100755
--- a/src/test/test_workqueue_cancel.sh
+++ b/src/test/test_workqueue_cancel.sh
@@ -1,4 +1,4 @@
#!/bin/sh
-${builddir:-.}/src/test/test_workqueue -C 1
+"${builddir:-.}/src/test/test_workqueue" -C 1
diff --git a/src/test/test_workqueue_efd.sh b/src/test/test_workqueue_efd.sh
index 4d89396819..592841fc91 100755
--- a/src/test/test_workqueue_efd.sh
+++ b/src/test/test_workqueue_efd.sh
@@ -1,4 +1,4 @@
#!/bin/sh
-${builddir:-.}/src/test/test_workqueue \
+"${builddir:-.}/src/test/test_workqueue" \
--no-eventfd2 --no-pipe2 --no-pipe --no-socketpair
diff --git a/src/test/test_workqueue_efd2.sh b/src/test/test_workqueue_efd2.sh
index 7cfff45ff3..4cf1b76cbe 100755
--- a/src/test/test_workqueue_efd2.sh
+++ b/src/test/test_workqueue_efd2.sh
@@ -1,4 +1,4 @@
#!/bin/sh
-${builddir:-.}/src/test/test_workqueue \
+"${builddir:-.}/src/test/test_workqueue" \
--no-eventfd --no-pipe2 --no-pipe --no-socketpair
diff --git a/src/test/test_workqueue_pipe.sh b/src/test/test_workqueue_pipe.sh
index afcef87853..fc3ef34c6c 100755
--- a/src/test/test_workqueue_pipe.sh
+++ b/src/test/test_workqueue_pipe.sh
@@ -1,4 +1,4 @@
#!/bin/sh
-${builddir:-.}/src/test/test_workqueue \
+"${builddir:-.}/src/test/test_workqueue" \
--no-eventfd2 --no-eventfd --no-pipe2 --no-socketpair
diff --git a/src/test/test_workqueue_pipe2.sh b/src/test/test_workqueue_pipe2.sh
index a20a1427e0..7f19ea880d 100755
--- a/src/test/test_workqueue_pipe2.sh
+++ b/src/test/test_workqueue_pipe2.sh
@@ -1,4 +1,4 @@
#!/bin/sh
-${builddir:-.}/src/test/test_workqueue \
+"${builddir:-.}/src/test/test_workqueue" \
--no-eventfd2 --no-eventfd --no-pipe --no-socketpair
diff --git a/src/test/test_workqueue_socketpair.sh b/src/test/test_workqueue_socketpair.sh
index 76af79746d..1ee1776447 100755
--- a/src/test/test_workqueue_socketpair.sh
+++ b/src/test/test_workqueue_socketpair.sh
@@ -1,4 +1,4 @@
#!/bin/sh
-${builddir:-.}/src/test/test_workqueue \
+"${builddir:-.}/src/test/test_workqueue" \
--no-eventfd2 --no-eventfd --no-pipe2 --no-pipe
diff --git a/src/test/test_x509.c b/src/test/test_x509.c
index 792849ae4b..94e7db33de 100644
--- a/src/test/test_x509.c
+++ b/src/test/test_x509.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2019, The Tor Project, Inc. */
+/* Copyright (c) 2010-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TOR_X509_PRIVATE
diff --git a/src/test/test_zero_length_keys.sh b/src/test/test_zero_length_keys.sh
index 84ca513b0a..b944d9bf3f 100755
--- a/src/test/test_zero_length_keys.sh
+++ b/src/test/test_zero_length_keys.sh
@@ -1,10 +1,44 @@
#!/bin/sh
# Check that tor regenerates keys when key files are zero-length
+umask 077
+set -e
+
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
+# find the tor binary
+if [ $# -ge 1 ]; then
+ TOR_BINARY="${1}"
+ shift
+else
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+if "$TOR_BINARY" --list-modules | grep -q "relay: no"; then
+ echo "This test requires the relay module. Skipping." >&2
+ exit 77
+fi
+
exitcode=0
-"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/app/tor" -z || exitcode=1
-"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/app/tor" -d || exitcode=1
-"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/app/tor" -e || exitcode=1
+"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "$TOR_BINARY" -z || exitcode=1
+"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "$TOR_BINARY" -d || exitcode=1
+"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "$TOR_BINARY" -e || exitcode=1
exit ${exitcode}
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index daa7aa524a..9b50de07a8 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,11 +12,13 @@
#include "orconfig.h"
#include "core/or/or.h"
#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "app/config/config.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "lib/err/backtrace.h"
#include "test/test.h"
@@ -25,6 +27,8 @@
#include "lib/compress/compress.h"
#include "lib/evloop/compat_libevent.h"
#include "lib/crypt_ops/crypto_init.h"
+#include "lib/version/torversion.h"
+#include "app/main/subsysmgr.h"
#include <stdio.h>
#ifdef HAVE_FCNTL_H
@@ -86,7 +90,18 @@ setup_directory(void)
(int)getpid(), rnd32);
r = mkdir(temp_dir);
}
-#else /* !(defined(_WIN32)) */
+#elif defined(__ANDROID__)
+ /* tor might not like the default perms, so create a subdir */
+ tor_snprintf(temp_dir, sizeof(temp_dir),
+ "/data/local/tmp/tor_%d_%d_%s",
+ (int) getuid(), (int) getpid(), rnd32);
+ r = mkdir(temp_dir, 0700);
+ if (r) {
+ fprintf(stderr, "Can't create directory %s:", temp_dir);
+ perror("");
+ exit(1);
+ }
+#else /* !defined(_WIN32) */
tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
(int) getpid(), rnd32);
r = mkdir(temp_dir, 0700);
@@ -94,7 +109,7 @@ setup_directory(void)
/* undo sticky bit so tests don't get confused. */
r = chown(temp_dir, getuid(), getgid());
}
-#endif /* defined(_WIN32) */
+#endif /* defined(_WIN32) || ... */
if (r) {
fprintf(stderr, "Can't create directory %s:", temp_dir);
perror("");
@@ -230,17 +245,17 @@ void
tinytest_prefork(void)
{
free_pregenerated_keys();
- crypto_prefork();
+ subsystems_prefork();
}
void
tinytest_postfork(void)
{
- crypto_postfork();
+ subsystems_postfork();
init_pregenerated_keys();
}
static void
-log_callback_failure(int severity, uint32_t domain, const char *msg)
+log_callback_failure(int severity, log_domain_mask_t domain, const char *msg)
{
(void)msg;
if (severity == LOG_ERR || (domain & LD_BUG)) {
@@ -259,24 +274,18 @@ main(int c, const char **v)
int loglevel = LOG_ERR;
int accel_crypto = 0;
- /* We must initialise logs before we call tor_assert() */
- init_logging(1);
+ subsystems_init();
- update_approx_time(time(NULL));
options = options_new();
- tor_threads_init();
- tor_compress_init();
-
- network_init();
-
- monotime_init();
- struct tor_libevent_cfg cfg;
+ struct tor_libevent_cfg_t cfg;
memset(&cfg, 0, sizeof(cfg));
tor_libevent_initialize(&cfg);
control_initialize_event_queue();
- configure_backtrace_handler(get_version());
+
+ /* Don't add default logs; the tests manage their own. */
+ quiet_level = QUIET_SILENT;
unsigned num=1, den=1;
@@ -316,7 +325,7 @@ main(int c, const char **v)
memset(&s, 0, sizeof(s));
set_log_severity_config(loglevel, LOG_ERR, &s);
/* ALWAYS log bug warnings. */
- s.masks[LOG_WARN-LOG_ERR] |= LD_BUG;
+ s.masks[SEVERITY_MASK_IDX(LOG_WARN)] |= LD_BUG;
add_stream_log(&s, "", fileno(stdout));
}
{
@@ -324,9 +333,10 @@ main(int c, const char **v)
log_severity_list_t s;
memset(&s, 0, sizeof(s));
set_log_severity_config(LOG_ERR, LOG_ERR, &s);
- s.masks[LOG_WARN-LOG_ERR] |= LD_BUG;
+ s.masks[SEVERITY_MASK_IDX(LOG_WARN)] |= LD_BUG;
add_callback_log(&s, log_callback_failure);
}
+ flush_log_messages_from_startup();
init_protocol_warning_severity_level();
options->command = CMD_RUN_UNITTESTS;
@@ -339,10 +349,12 @@ main(int c, const char **v)
return 1;
}
rep_hist_init();
+ bwhist_init();
setup_directory();
initialize_mainloop_events();
options_init(options);
options->DataDirectory = tor_strdup(temp_dir);
+ options->DataDirectory_option = tor_strdup(temp_dir);
tor_asprintf(&options->KeyDirectory, "%s"PATH_SEPARATOR"keys",
options->DataDirectory);
options->CacheDirectory = tor_strdup(temp_dir);
@@ -409,8 +421,6 @@ main(int c, const char **v)
free_pregenerated_keys();
- crypto_global_cleanup();
-
if (have_failed)
return 1;
else
diff --git a/src/test/testing_rsakeys.c b/src/test/testing_rsakeys.c
index 0f22d4e01b..e058f72d01 100644
--- a/src/test/testing_rsakeys.c
+++ b/src/test/testing_rsakeys.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "lib/crypt_ops/crypto_rand.h"
@@ -448,7 +448,8 @@ static int next_key_idx_2048;
static crypto_pk_t *
pk_generate_internal(int bits)
{
- tor_assert(bits == 2048 || bits == 1024);
+ tor_assertf(bits == 2048 || bits == 1024,
+ "Wrong key size: %d", bits);
#ifdef USE_PREGENERATED_RSA_KEYS
int *idxp;
@@ -467,7 +468,7 @@ pk_generate_internal(int bits)
*idxp += crypto_rand_int_range(1,3);
*idxp %= n_pregen;
return crypto_pk_dup_key(pregen_array[*idxp]);
-#else /* !(defined(USE_PREGENERATED_RSA_KEYS)) */
+#else /* !defined(USE_PREGENERATED_RSA_KEYS) */
crypto_pk_t *result;
int res;
result = crypto_pk_new();
diff --git a/src/test/vote_descriptors.inc b/src/test/vote_descriptors.inc
index 895dc6c65c..51cf465170 100644
--- a/src/test/vote_descriptors.inc
+++ b/src/test/vote_descriptors.inc
@@ -1,3 +1,6 @@
+/* Not sure where we got this; it appears to be hand-generated and signed.
+ * It's been edited so that the signature doesn't verify any more;
+ * you need to mock check_signature_token for this to work. */
static const char* VOTE_BODY_V3 =
"network-status-version 3\n"
"vote-status vote\n"
@@ -60,6 +63,7 @@ static const char* VOTE_BODY_V3 =
"w Bandwidth=30 Measured=30\n"
"p reject 1-65535\n"
"id ed25519 none\n"
+"pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5\n"
"m 9,10,11,12,13,14,15,16,17 sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa0\n"
"r router1 BQUFBQUFBQUFBQUFBQUFBQUFBQU TU1NTU1NTU1NTU1NTU1NTU1NTU0 2015-09-02 19:17:35 153.0.153.1 443 0\n"
"a [1:2:3::4]:4711\n"
@@ -68,6 +72,7 @@ static const char* VOTE_BODY_V3 =
"w Bandwidth=120 Measured=120\n"
"p reject 1-65535\n"
"id ed25519 none\n"
+"pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5\n"
"m 9,10,11,12,13,14,15,16,17 sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa1\n"
"r router3 MzMzMzMzMzMzMzMzMzMzMzMzMzM T09PT09PT09PT09PT09PT09PT08 2015-09-02 19:17:35 170.0.153.1 400 9999\n"
"s Authority Exit Fast Guard Running Stable V2Dir Valid\n"
@@ -75,6 +80,7 @@ static const char* VOTE_BODY_V3 =
"w Bandwidth=120\n"
"p reject 1-65535\n"
"id ed25519 none\n"
+"pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5\n"
"m 9,10,11,12,13,14,15,16,17 "
"sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa2\n"
"r router4 NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ Ly8vLy8vLy8vLy8vLy8vLy8vLy8 2015-09-02 19:17:35 192.0.2.3 500 1999\n"
@@ -83,6 +89,7 @@ static const char* VOTE_BODY_V3 =
"w Bandwidth=30\n"
"p reject 1-65535\n"
"id ed25519 none\n"
+"pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5\n"
"m 9,10,11,12,13,14,15,16,17 sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa3\n"
"directory-footer\n"
"directory-signature D867ACF56A9D229B35C25F0090BC9867E906BE69 CBF56A83368A5150F1A9AAADAFB4D77F8C4170E2\n"
@@ -91,4 +98,3 @@ static const char* VOTE_BODY_V3 =
"TXQWGUq9Z7jdSVnzWT3xqPA4zjw6eZkj+DKUtwq+oEDZGlf8eHTFmr0NAWfwZbk9\n"
"NAjbMTUXUP37N2XAZwkoCWwFCrrfMwXrL7OhZbj7ifo=\n"
"-----END SIGNATURE-----\n";
-
diff --git a/src/test/zero_length_keys.sh b/src/test/zero_length_keys.sh
index 5635bdfd89..1702d11245 100755
--- a/src/test/zero_length_keys.sh
+++ b/src/test/zero_length_keys.sh
@@ -19,7 +19,7 @@
# 3: a command failed - the test could not be completed
#
-if [ $# -eq 0 ] || [ ! -f ${1} ] || [ ! -x ${1} ]; then
+if [ $# -eq 0 ] || [ ! -f "${1}" ] || [ ! -x "${1}" ]; then
echo "Usage: ${0} PATH_TO_TOR [-z|-d|-e]"
exit 1
elif [ $# -eq 1 ]; then
@@ -31,7 +31,7 @@ else #[$# -gt 1 ]; then
shift
fi
-DATA_DIR=`mktemp -d -t tor_zero_length_keys.XXXXXX`
+DATA_DIR=$(mktemp -d -t tor_zero_length_keys.XXXXXX)
if [ -z "$DATA_DIR" ]; then
echo "Failure: mktemp invocation returned empty string" >&2
exit 3
@@ -40,7 +40,7 @@ if [ ! -d "$DATA_DIR" ]; then
echo "Failure: mktemp invocation result doesn't point to directory" >&2
exit 3
fi
-trap "rm -rf '$DATA_DIR'" 0
+trap 'rm -rf "$DATA_DIR"' 0
touch "$DATA_DIR"/empty_torrc
touch "$DATA_DIR"/empty_defaults_torrc