diff options
Diffstat (limited to 'src/test')
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 = ¶ms->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(ô->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(ô->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(ô->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(ô->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(ô->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(ô->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(ô->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", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); valid_until_time = get_state_valid_until_time(current_time); /* Compare it with the correct result */ @@ -213,7 +216,7 @@ test_get_state_valid_until_time(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 19:22:00 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); valid_until_time = get_state_valid_until_time(current_time); format_iso_time(tbuf, valid_until_time); @@ -224,7 +227,7 @@ test_get_state_valid_until_time(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:00 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); valid_until_time = get_state_valid_until_time(current_time); format_iso_time(tbuf, valid_until_time); @@ -235,7 +238,7 @@ test_get_state_valid_until_time(void *arg) retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); valid_until_time = get_state_valid_until_time(current_time); format_iso_time(tbuf, valid_until_time); @@ -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", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); run_start_time = sr_state_get_start_time_of_current_protocol_run(); /* Compare it with the correct result */ @@ -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", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); run_start_time = sr_state_get_start_time_of_current_protocol_run(); /* Compare it with the correct result */ @@ -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", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); run_start_time = sr_state_get_start_time_of_current_protocol_run(); /* Compare it with the correct result */ @@ -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", ¤t_time); tt_int_op(retval, OP_EQ, 0); update_approx_time(current_time); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); run_start_time = sr_state_get_start_time_of_current_protocol_run(); @@ -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", ¤t_time); tt_int_op(retval, OP_EQ, 0); - voting_schedule_recalculate_timing(get_options(), current_time); + dirauth_sched_recalculate_timing(get_options(), current_time); run_start_time = sr_state_get_start_time_of_current_protocol_run(); /* Compare it with the correct result */ @@ -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 |