diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/bench.c | 4 | ||||
-rw-r--r-- | src/test/include.am | 5 | ||||
-rw-r--r-- | src/test/log_test_helpers.c | 118 | ||||
-rw-r--r-- | src/test/log_test_helpers.h | 20 | ||||
-rw-r--r-- | src/test/sr_commit_calc_ref.py | 51 | ||||
-rw-r--r-- | src/test/test-memwipe.c | 13 | ||||
-rw-r--r-- | src/test/test.c | 1 | ||||
-rw-r--r-- | src/test/test.h | 1 | ||||
-rw-r--r-- | src/test/test_addr.c | 8 | ||||
-rw-r--r-- | src/test/test_address.c | 5 | ||||
-rw-r--r-- | src/test/test_compat_libevent.c | 12 | ||||
-rw-r--r-- | src/test/test_config.c | 2 | ||||
-rw-r--r-- | src/test/test_crypto.c | 2 | ||||
-rw-r--r-- | src/test/test_dir.c | 24 | ||||
-rw-r--r-- | src/test/test_link_handshake.c | 105 | ||||
-rw-r--r-- | src/test/test_oos.c | 456 | ||||
-rw-r--r-- | src/test/test_shared_random.c | 44 | ||||
-rw-r--r-- | src/test/test_tortls.c | 2 | ||||
-rw-r--r-- | src/test/test_util.c | 273 | ||||
-rw-r--r-- | src/test/testing_common.c | 4 |
20 files changed, 957 insertions, 193 deletions
diff --git a/src/test/bench.c b/src/test/bench.c index f1cf715f30..f373019b95 100644 --- a/src/test/bench.c +++ b/src/test/bench.c @@ -557,7 +557,7 @@ bench_dh(void) dh_b, dh_pubkey_a, sizeof(dh_pubkey_a), secret_b, sizeof(secret_b)); tor_assert(slen_a == slen_b); - tor_assert(!memcmp(secret_a, secret_b, slen_a)); + tor_assert(fast_memeq(secret_a, secret_b, slen_a)); crypto_dh_free(dh_a); crypto_dh_free(dh_b); } @@ -595,7 +595,7 @@ bench_ecdh_impl(int nid, const char *name) NULL); tor_assert(slen_a == slen_b); - tor_assert(!memcmp(secret_a, secret_b, slen_a)); + tor_assert(fast_memeq(secret_a, secret_b, slen_a)); EC_KEY_free(dh_a); EC_KEY_free(dh_b); } diff --git a/src/test/include.am b/src/test/include.am index d0bc808877..0aff395091 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -28,9 +28,9 @@ TESTS += src/test/test 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-min bridges+hs +TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-min # only run if we can ping6 ::1 (localhost) -TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min +TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-ipv6 # only run if we can find a stable (or simply another) version of tor TEST_CHUTNEY_FLAVORS_MIXED = mixed @@ -103,6 +103,7 @@ src_test_test_SOURCES = \ src/test/test_microdesc.c \ src/test/test_nodelist.c \ src/test/test_oom.c \ + src/test/test_oos.c \ src/test/test_options.c \ src/test/test_policy.c \ src/test/test_procmon.c \ diff --git a/src/test/log_test_helpers.c b/src/test/log_test_helpers.c index 166a777747..1ad008aa50 100644 --- a/src/test/log_test_helpers.c +++ b/src/test/log_test_helpers.c @@ -4,19 +4,74 @@ #include "torlog.h" #include "log_test_helpers.h" +/** + * \file log_test_helpers.c + * \brief Code to check for expected log messages during testing. + */ + +static void mock_saving_logv(int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, + const char *format, va_list ap) + CHECK_PRINTF(5, 0); + +/** + * Smartlist of all the logs we've received since we last set up + * log capture. + */ static smartlist_t *saved_logs = NULL; +/** Boolean: should we also send messages to the test-runner? */ +static int echo_to_real_logs = 1; + +/** Record logs at this level or more severe */ +static int record_logs_at_level = LOG_ERR; + +/** + * As setup_capture_of_logs, but do not relay log messages into the main + * logging system. + * + * Avoid using this function; use setup_capture_of_logs() instead if you + * can. If you must use this function, then make sure you detect any + * unexpected log messages, and treat them as test failures. */ +int +setup_full_capture_of_logs(int new_level) +{ + int result = setup_capture_of_logs(new_level); + echo_to_real_logs = 0; + return result; +} + +/** + * Temporarily capture all the messages logged at severity <b>new_level</b> or + * higher. Return the previous log level; you'll need to pass it into + * teardown_capture_of_logs(). + * + * This function does not prevent messages from being sent to the main + * logging system. + */ int setup_capture_of_logs(int new_level) { int previous_log = log_global_min_severity_; - log_global_min_severity_ = new_level; + + /* Only change the log_global_min_severity_ if we're making things _more_ + * verbose. Otherwise we could prevent real log messages that the test- + * runner wanted. + */ + if (log_global_min_severity_ < new_level) + log_global_min_severity_ = new_level; + + record_logs_at_level = new_level; mock_clean_saved_logs(); saved_logs = smartlist_new(); MOCK(logv, mock_saving_logv); + echo_to_real_logs = 1; return previous_log; } +/** + * Undo setup_capture_of_logs(). + */ void teardown_capture_of_logs(int prev) { @@ -25,6 +80,9 @@ teardown_capture_of_logs(int prev) mock_clean_saved_logs(); } +/** + * Clear all messages in mock_saved_logs() + */ void mock_clean_saved_logs(void) { @@ -36,30 +94,58 @@ mock_clean_saved_logs(void) saved_logs = NULL; } +/** + * Return a list of all the messages captured since the last + * setup_[full_]capture_of_logs() call. Each log call is recorded as a + * mock_saved_log_entry_t. + */ const smartlist_t * mock_saved_logs(void) { return saved_logs; } +/** + * Return true iff there is a message recorded by log capture + * that is exactly equal to <b>msg</b> + */ int mock_saved_log_has_message(const char *msg) { - int has_msg = 0; if (saved_logs) { SMARTLIST_FOREACH(saved_logs, mock_saved_log_entry_t *, m, { if (msg && m->generated_msg && !strcmp(msg, m->generated_msg)) { - has_msg = 1; + return 1; } }); } - return has_msg; + return 0; } -/* Do the saved logs have any messages with severity? */ +/** + * Return true iff there is a message recorded by log capture + * that contains <b>msg</b> as a substring. + */ +int +mock_saved_log_has_message_containing(const char *msg) +{ + if (saved_logs) { + SMARTLIST_FOREACH(saved_logs, mock_saved_log_entry_t *, m, + { + if (msg && m->generated_msg && + strstr(m->generated_msg, msg)) { + return 1; + } + }); + } + + return 0; +} + +/** Return true iff the saved logs have any messages with <b>severity</b> */ int mock_saved_log_has_severity(int severity) { @@ -76,7 +162,7 @@ mock_saved_log_has_severity(int severity) return has_sev; } -/* Do the saved logs have any messages? */ +/** Return true iff the the saved logs have at lease one message */ int mock_saved_log_has_entry(void) { @@ -86,12 +172,14 @@ mock_saved_log_has_entry(void) return 0; } -void +/* Replacement for logv: record the log message, and (maybe) send it + * into the logging system again. + */ +static void mock_saving_logv(int severity, log_domain_mask_t domain, const char *funcname, const char *suffix, const char *format, va_list ap) { - (void)domain; char *buf = tor_malloc_zero(10240); int n; n = tor_vsnprintf(buf,10240,format,ap); @@ -99,6 +187,18 @@ mock_saving_logv(int severity, log_domain_mask_t domain, buf[n]='\n'; buf[n+1]='\0'; + if (echo_to_real_logs) { + tor_log(severity, domain|LD_NO_MOCK, "%s", buf); + } + + if (severity > record_logs_at_level) { + tor_free(buf); + return; + } + + if (!saved_logs) + saved_logs = smartlist_new(); + mock_saved_log_entry_t *e = tor_malloc_zero(sizeof(mock_saved_log_entry_t)); e->severity = severity; e->funcname = funcname; @@ -107,8 +207,6 @@ mock_saving_logv(int severity, log_domain_mask_t domain, e->generated_msg = tor_strdup(buf); tor_free(buf); - if (!saved_logs) - saved_logs = smartlist_new(); smartlist_add(saved_logs, e); } diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h index 1966f170fb..f33ee67a90 100644 --- a/src/test/log_test_helpers.h +++ b/src/test/log_test_helpers.h @@ -6,25 +6,24 @@ #ifndef TOR_LOG_TEST_HELPERS_H #define TOR_LOG_TEST_HELPERS_H +/** An element of mock_saved_logs(); records the log element that we + * received. */ typedef struct mock_saved_log_entry_t { int severity; const char *funcname; const char *suffix; const char *format; char *generated_msg; - struct mock_saved_log_entry_t *next; } mock_saved_log_entry_t; -void mock_saving_logv(int severity, log_domain_mask_t domain, - const char *funcname, const char *suffix, - const char *format, va_list ap) - CHECK_PRINTF(5, 0); void mock_clean_saved_logs(void); const smartlist_t *mock_saved_logs(void); int setup_capture_of_logs(int new_level); +int setup_full_capture_of_logs(int new_level); void teardown_capture_of_logs(int prev); int mock_saved_log_has_message(const char *msg); +int mock_saved_log_has_message_containing(const char *msg); int mock_saved_log_has_severity(int severity); int mock_saved_log_has_entry(void); @@ -32,6 +31,17 @@ int mock_saved_log_has_entry(void); tt_assert_msg(mock_saved_log_has_message(str), \ "expected log to contain " # str); +#define expect_log_msg_containing(str) \ + tt_assert_msg(mock_saved_log_has_message_containing(str), \ + "expected log to contain " # str); + +#define expect_single_log_msg_containing(str) \ + do { \ + tt_assert_msg(mock_saved_log_has_message_containing(str), \ + "expected log to contain " # str); \ + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); \ + } while (0); + #define expect_no_log_msg(str) \ tt_assert_msg(!mock_saved_log_has_message(str), \ "expected log to not contain " # str); diff --git a/src/test/sr_commit_calc_ref.py b/src/test/sr_commit_calc_ref.py new file mode 100644 index 0000000000..45e629cfb0 --- /dev/null +++ b/src/test/sr_commit_calc_ref.py @@ -0,0 +1,51 @@ +# This is a reference implementation of the COMMIT/REVEAL calculation for +# prop250. We use it to generate a test vector for the test_encoding() +# unittest. +# +# Here is the computation formula: +# +# H = SHA3-256 +# TIMESTAMP = 8 bytes network-endian value +# RAND = H(32 bytes of random) +# +# REVEAL = base64-encode( TIMESTAMP || RAND ) +# COMMIT = base64-encode( TIMESTAMP || H(REVEAL) ) +# + +import sys +import hashlib +import struct +import base64 + +# Python 3.6+, the SHA3 is available in hashlib natively. Else this requires +# the pysha3 package (pip install pysha3). +if sys.version_info < (3, 6): + import sha3 + +# Test vector to make sure the right sha3 version will be used. pysha3 < 1.0 +# used the old Keccak implementation. During the finalization of SHA3, NIST +# changed the delimiter suffix from 0x01 to 0x06. The Keccak sponge function +# stayed the same. pysha3 1.0 provides the previous Keccak hash, too. +TEST_VALUE = "e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51" +if TEST_VALUE != sha3.sha3_256(b"Hello World").hexdigest(): + print("pysha3 version is < 1.0. Please install from:") + print("https://github.com/tiran/pysha3https://github.com/tiran/pysha3") + sys.exit(1) + +# TIMESTAMP +ts = 1454333590 +# RAND +data = 'A' * 32 # Yes very very random, NIST grade :). +rand = hashlib.sha3_256(data) + +reveal = struct.pack('!Q', ts) + rand.digest() +b64_reveal = base64.b64encode(reveal) +print("REVEAL: %s" % (b64_reveal)) + +# Yes we do hash the _encoded_ reveal here that is H(REVEAL) +hashed_reveal = hashlib.sha3_256(b64_reveal) +commit = struct.pack('!Q', ts) + hashed_reveal.digest() +print("COMMIT: %s" % (base64.b64encode(commit))) + +# REVEAL: AAAAAFavXpZJxbwTupvaJCTeIUCQmOPxAMblc7ChL5H2nZKuGchdaA== +# COMMIT: AAAAAFavXpbkBMzMQG7aNoaGLFNpm2Wkk1ozXhuWWqL//GynltxVAg== diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c index c28d5054a2..2d40283fb1 100644 --- a/src/test/test-memwipe.c +++ b/src/test/test-memwipe.c @@ -5,6 +5,7 @@ #include "crypto.h" #include "compat.h" +#include "util.h" static unsigned fill_a_buffer_memset(void) __attribute__((noinline)); static unsigned fill_a_buffer_memwipe(void) __attribute__((noinline)); @@ -98,29 +99,29 @@ static char *heap_buf = NULL; static unsigned fill_heap_buffer_memset(void) { - char *buf = heap_buf = malloc(BUF_LEN); + char *buf = heap_buf = raw_malloc(BUF_LEN); FILL_BUFFER_IMPL() memset(buf, 0, BUF_LEN); - free(buf); + raw_free(buf); return sum; } static unsigned fill_heap_buffer_memwipe(void) { - char *buf = heap_buf = malloc(BUF_LEN); + char *buf = heap_buf = raw_malloc(BUF_LEN); FILL_BUFFER_IMPL() memwipe(buf, 0, BUF_LEN); - free(buf); + raw_free(buf); return sum; } static unsigned fill_heap_buffer_nothing(void) { - char *buf = heap_buf = malloc(BUF_LEN); + char *buf = heap_buf = raw_malloc(BUF_LEN); FILL_BUFFER_IMPL() - free(buf); + raw_free(buf); return sum; } diff --git a/src/test/test.c b/src/test/test.c index f8610168f6..2f10c7e90b 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1210,6 +1210,7 @@ struct testgroup_t testgroups[] = { { "link-handshake/", link_handshake_tests }, { "nodelist/", nodelist_tests }, { "oom/", oom_tests }, + { "oos/", oos_tests }, { "options/", options_tests }, { "policy/" , policy_tests }, { "procmon/", procmon_tests }, diff --git a/src/test/test.h b/src/test/test.h index 6744d255f1..c0643e154d 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -202,6 +202,7 @@ extern struct testcase_t logging_tests[]; extern struct testcase_t microdesc_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 policy_tests[]; extern struct testcase_t procmon_tests[]; diff --git a/src/test/test_addr.c b/src/test/test_addr.c index dcecb0b7dc..c8a9e6d384 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -81,7 +81,7 @@ test_addr_basic(void *arg) #define test_op_ip6_(a,op,b,e1,e2) \ STMT_BEGIN \ tt_assert_test_fmt_type(a,b,e1" "#op" "e2,struct in6_addr*, \ - (memcmp(val1_->s6_addr, val2_->s6_addr, 16) op 0), \ + (fast_memcmp(val1_->s6_addr, val2_->s6_addr, 16) op 0), \ char *, "%s", \ { char *cp; \ cp = print_ = tor_malloc(64); \ @@ -1037,17 +1037,17 @@ test_addr_make_null(void *data) (void) data; /* Ensure that before tor_addr_make_null, addr != 0's */ memset(addr, 1, sizeof(*addr)); - tt_int_op(memcmp(addr, zeros, sizeof(*addr)), OP_NE, 0); + tt_int_op(fast_memcmp(addr, zeros, sizeof(*addr)), OP_NE, 0); /* Test with AF == AF_INET */ zeros->family = AF_INET; tor_addr_make_null(addr, AF_INET); - tt_int_op(memcmp(addr, zeros, sizeof(*addr)), OP_EQ, 0); + tt_int_op(fast_memcmp(addr, zeros, sizeof(*addr)), OP_EQ, 0); tt_str_op(tor_addr_to_str(buf, addr, sizeof(buf), 0), OP_EQ, "0.0.0.0"); /* Test with AF == AF_INET6 */ memset(addr, 1, sizeof(*addr)); zeros->family = AF_INET6; tor_addr_make_null(addr, AF_INET6); - tt_int_op(memcmp(addr, zeros, sizeof(*addr)), OP_EQ, 0); + tt_int_op(fast_memcmp(addr, zeros, sizeof(*addr)), OP_EQ, 0); tt_str_op(tor_addr_to_str(buf, addr, sizeof(buf), 0), OP_EQ, "::"); done: tor_free(addr); diff --git a/src/test/test_address.c b/src/test/test_address.c index b4638f0702..e984beab46 100644 --- a/src/test/test_address.c +++ b/src/test/test_address.c @@ -824,9 +824,12 @@ test_address_get_if_addrs6_list_no_internal(void *arg) (void)arg; /* We might drop a log_err */ - int prev_level = setup_capture_of_logs(LOG_ERR); + int prev_level = setup_full_capture_of_logs(LOG_ERR); results = get_interface_address6_list(LOG_ERR, AF_INET6, 0); tt_int_op(smartlist_len(mock_saved_logs()), OP_LE, 1); + if (smartlist_len(mock_saved_logs()) == 1) { + expect_log_msg_containing("connect() failed"); + } teardown_capture_of_logs(prev_level); tt_assert(results != NULL); diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c index f13eb81124..5e14be5b33 100644 --- a/src/test/test_compat_libevent.c +++ b/src/test/test_compat_libevent.c @@ -20,31 +20,36 @@ static void test_compat_libevent_logging_callback(void *ignored) { (void)ignored; - int previous_log = setup_capture_of_logs(LOG_DEBUG); + int previous_log = setup_full_capture_of_logs(LOG_DEBUG); libevent_logging_callback(_EVENT_LOG_DEBUG, "hello world"); expect_log_msg("Message from libevent: hello world\n"); expect_log_severity(LOG_DEBUG); + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); mock_clean_saved_logs(); libevent_logging_callback(_EVENT_LOG_MSG, "hello world another time"); expect_log_msg("Message from libevent: hello world another time\n"); expect_log_severity(LOG_INFO); + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); mock_clean_saved_logs(); libevent_logging_callback(_EVENT_LOG_WARN, "hello world a third time"); expect_log_msg("Warning from libevent: hello world a third time\n"); expect_log_severity(LOG_WARN); + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); mock_clean_saved_logs(); libevent_logging_callback(_EVENT_LOG_ERR, "hello world a fourth time"); expect_log_msg("Error from libevent: hello world a fourth time\n"); expect_log_severity(LOG_ERR); + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); mock_clean_saved_logs(); libevent_logging_callback(42, "hello world a fifth time"); expect_log_msg("Message [42] from libevent: hello world a fifth time\n"); expect_log_severity(LOG_WARN); + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); mock_clean_saved_logs(); libevent_logging_callback(_EVENT_LOG_DEBUG, @@ -75,21 +80,26 @@ test_compat_libevent_logging_callback(void *ignored) "012345678901234567890123456789" "012345678901234567890123456789\n"); expect_log_severity(LOG_DEBUG); + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); mock_clean_saved_logs(); libevent_logging_callback(42, "xxx\n"); expect_log_msg("Message [42] from libevent: xxx\n"); expect_log_severity(LOG_WARN); + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); suppress_libevent_log_msg("something"); mock_clean_saved_logs(); libevent_logging_callback(_EVENT_LOG_MSG, "hello there"); expect_log_msg("Message from libevent: hello there\n"); expect_log_severity(LOG_INFO); + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); mock_clean_saved_logs(); libevent_logging_callback(_EVENT_LOG_MSG, "hello there something else"); expect_no_log_msg("hello there something else"); + if (mock_saved_logs()) + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 0); // No way of verifying the result of this, it seems =/ configure_libevent_logging(); diff --git a/src/test/test_config.c b/src/test/test_config.c index 619477ca7d..80a172789b 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -3832,6 +3832,8 @@ test_config_parse_port_config__listenaddress(void *data) tt_int_op(ret, OP_EQ, 0); // Test warning nonlocal other + SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); + smartlist_clear(slout); ret = parse_port_config(slout, config_port2, config_listen_address, "DNS", 0, NULL, 0, CL_PORT_WARN_NONLOCAL); tt_int_op(ret, OP_EQ, 0); diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 542512bd44..9cae1e8dd8 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -2258,7 +2258,7 @@ test_crypto_ed25519_simple(void *arg) tt_int_op(0, OP_EQ, ed25519_sign(&manual_sig, (uint8_t *)prefixed_msg, strlen(prefixed_msg), &kp1)); tor_free(prefixed_msg); - tt_assert(!memcmp(sig1.sig, manual_sig.sig, sizeof(sig1.sig))); + tt_assert(fast_memeq(sig1.sig, manual_sig.sig, sizeof(sig1.sig))); /* Test that prefixed checksig verifies it properly. */ tt_int_op(0, OP_EQ, ed25519_checksig_prefixed(&sig1, msg, msg_len, diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 51a5ecad76..bfd89a917a 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -116,6 +116,7 @@ test_dir_formats(void *arg) 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); @@ -135,6 +136,11 @@ test_dir_formats(void *arg) tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::"); r1->ipv6_orport = 9999; r1->onion_pkey = crypto_pk_dup_key(pk1); + /* 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, + sizeof(curve25519_public_key_t)); r1->identity_pkey = crypto_pk_dup_key(pk2); r1->bandwidthrate = 1000; r1->bandwidthburst = 5000; @@ -167,11 +173,6 @@ test_dir_formats(void *arg) &kp2.pubkey, now, 86400, CERT_FLAG_INCLUDE_SIGNING_KEY); - char cert_buf[256]; - 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); r2->platform = tor_strdup(platform); r2->cache_info.published_on = 5; r2->or_port = 9005; @@ -247,6 +248,11 @@ test_dir_formats(void *arg) 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 @@ -276,6 +282,10 @@ test_dir_formats(void *arg) "router Fred 10.3.2.1 9005 0 0\n" "identity-ed25519\n" "-----BEGIN ED25519 CERT-----\n", sizeof(buf2)); + 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)); @@ -2042,9 +2052,9 @@ test_a_networkstatus( tt_int_op(4,OP_EQ, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/ /* The voter id digests should be in this order. */ - tt_assert(memcmp(cert2->cache_info.identity_digest, + tt_assert(fast_memcmp(cert2->cache_info.identity_digest, cert1->cache_info.identity_digest,DIGEST_LEN)<0); - tt_assert(memcmp(cert1->cache_info.identity_digest, + tt_assert(fast_memcmp(cert1->cache_info.identity_digest, cert3->cache_info.identity_digest,DIGEST_LEN)<0); test_same_voter(smartlist_get(con->voters, 1), smartlist_get(v2->voters, 0)); diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c index 4038783459..e1fd14bc5f 100644 --- a/src/test/test_link_handshake.c +++ b/src/test/test_link_handshake.c @@ -15,6 +15,7 @@ #include "scheduler.h" #include "test.h" +#include "log_test_helpers.h" static var_cell_t *mock_got_var_cell = NULL; @@ -173,6 +174,8 @@ test_link_handshake_certs_ok(void *arg) UNMOCK(tor_tls_cert_matches_key); UNMOCK(connection_or_write_var_cell_to_buf); UNMOCK(connection_or_send_netinfo); + memset(c1->identity_digest, 0, sizeof(c1->identity_digest)); + memset(c2->identity_digest, 0, sizeof(c2->identity_digest)); connection_free_(TO_CONN(c1)); connection_free_(TO_CONN(c2)); tor_free(cell1); @@ -209,6 +212,7 @@ recv_certs_cleanup(const struct testcase_t *test, void *obj) if (d) { tor_free(d->cell); certs_cell_free(d->ccell); + connection_or_remove_from_identity_map(d->c); connection_free_(TO_CONN(d->c)); circuitmux_free(d->chan->base_.cmux); tor_free(d->chan); @@ -332,30 +336,51 @@ test_link_handshake_recv_certs_ok_server(void *arg) test_link_handshake_recv_certs_ ## name(void *arg) \ { \ certs_data_t *d = arg; \ + const char *require_failure_message = NULL; \ + const int prev_level = setup_capture_of_logs(LOG_INFO); \ { code ; } \ channel_tls_process_certs_cell(d->cell, d->chan); \ tt_int_op(1, ==, mock_close_called); \ tt_int_op(0, ==, mock_send_authenticate_called); \ tt_int_op(0, ==, mock_send_netinfo_called); \ + if (require_failure_message) { \ + tt_assert(mock_saved_log_has_message_containing( \ + require_failure_message)); \ + } \ done: \ - ; \ + teardown_capture_of_logs(prev_level); \ } -CERTS_FAIL(badstate, d->c->base_.state = OR_CONN_STATE_CONNECTING) -CERTS_FAIL(badproto, d->c->link_proto = 2) -CERTS_FAIL(duplicate, d->c->handshake_state->received_certs_cell = 1) +CERTS_FAIL(badstate, + require_failure_message = "We're not doing a v3 handshake!"; + d->c->base_.state = OR_CONN_STATE_CONNECTING;) +CERTS_FAIL(badproto, + require_failure_message = "not using link protocol >= 3"; + d->c->link_proto = 2) +CERTS_FAIL(duplicate, + require_failure_message = "We already got one"; + d->c->handshake_state->received_certs_cell = 1) CERTS_FAIL(already_authenticated, + require_failure_message = "We're already authenticated!"; d->c->handshake_state->authenticated = 1) -CERTS_FAIL(empty, d->cell->payload_len = 0) -CERTS_FAIL(bad_circid, d->cell->circ_id = 1) -CERTS_FAIL(truncated_1, d->cell->payload[0] = 5) +CERTS_FAIL(empty, + require_failure_message = "It had no body"; + d->cell->payload_len = 0) +CERTS_FAIL(bad_circid, + require_failure_message = "It had a nonzero circuit ID"; + d->cell->circ_id = 1) +CERTS_FAIL(truncated_1, + require_failure_message = "It couldn't be parsed"; + d->cell->payload[0] = 5) CERTS_FAIL(truncated_2, { + require_failure_message = "It couldn't be parsed"; d->cell->payload_len = 4; memcpy(d->cell->payload, "\x01\x01\x00\x05", 4); }) CERTS_FAIL(truncated_3, { + require_failure_message = "It couldn't be parsed"; d->cell->payload_len = 7; memcpy(d->cell->payload, "\x01\x01\x00\x05""abc", 7); }) @@ -367,30 +392,35 @@ CERTS_FAIL(truncated_3, CERTS_FAIL(not_x509, { + require_failure_message = "Received undecodable certificate"; certs_cell_cert_setlen_body(certs_cell_get_certs(d->ccell, 0), 3); certs_cell_get_certs(d->ccell, 0)->cert_len = 3; REENCODE(); }) CERTS_FAIL(both_link, { + require_failure_message = "Duplicate x509 certificate"; certs_cell_get_certs(d->ccell, 0)->cert_type = 1; certs_cell_get_certs(d->ccell, 1)->cert_type = 1; REENCODE(); }) CERTS_FAIL(both_id_rsa, { + require_failure_message = "Duplicate x509 certificate"; certs_cell_get_certs(d->ccell, 0)->cert_type = 2; certs_cell_get_certs(d->ccell, 1)->cert_type = 2; REENCODE(); }) CERTS_FAIL(both_auth, { + require_failure_message = "Duplicate x509 certificate"; certs_cell_get_certs(d->ccell, 0)->cert_type = 3; certs_cell_get_certs(d->ccell, 1)->cert_type = 3; REENCODE(); }) CERTS_FAIL(wrong_labels_1, { + require_failure_message = "The link certificate was not valid"; certs_cell_get_certs(d->ccell, 0)->cert_type = 2; certs_cell_get_certs(d->ccell, 1)->cert_type = 1; REENCODE(); @@ -401,6 +431,7 @@ CERTS_FAIL(wrong_labels_2, const tor_x509_cert_t *b; const uint8_t *enca; size_t lena; + require_failure_message = "The link certificate was not valid"; tor_tls_get_my_certs(1, &a, &b); tor_x509_cert_get_der(a, &enca, &lena); certs_cell_cert_setlen_body(certs_cell_get_certs(d->ccell, 1), lena); @@ -411,16 +442,20 @@ CERTS_FAIL(wrong_labels_2, }) CERTS_FAIL(wrong_labels_3, { + require_failure_message = "The certs we wanted were missing"; certs_cell_get_certs(d->ccell, 0)->cert_type = 2; certs_cell_get_certs(d->ccell, 1)->cert_type = 3; REENCODE(); }) CERTS_FAIL(server_missing_certs, { + require_failure_message = "The certs we wanted were missing"; d->c->handshake_state->started_here = 0; }) CERTS_FAIL(server_wrong_labels_1, { + require_failure_message = + "The authentication certificate was not valid"; d->c->handshake_state->started_here = 0; certs_cell_get_certs(d->ccell, 0)->cert_type = 2; certs_cell_get_certs(d->ccell, 1)->cert_type = 3; @@ -579,30 +614,47 @@ test_link_handshake_recv_authchallenge_ok_unrecognized(void *arg) test_link_handshake_recv_authchallenge_ ## name(void *arg) \ { \ authchallenge_data_t *d = arg; \ + const char *require_failure_message = NULL; \ + const int prev_level = setup_capture_of_logs(LOG_INFO); \ { code ; } \ channel_tls_process_auth_challenge_cell(d->cell, d->chan); \ tt_int_op(1, ==, mock_close_called); \ tt_int_op(0, ==, mock_send_authenticate_called); \ tt_int_op(0, ==, mock_send_netinfo_called); \ + if (require_failure_message) { \ + tt_assert(mock_saved_log_has_message_containing( \ + require_failure_message)); \ + } \ done: \ - ; \ + teardown_capture_of_logs(prev_level); \ } AUTHCHALLENGE_FAIL(badstate, + require_failure_message = "We're not currently doing a " + "v3 handshake"; d->c->base_.state = OR_CONN_STATE_CONNECTING) AUTHCHALLENGE_FAIL(badproto, + require_failure_message = "not using link protocol >= 3"; d->c->link_proto = 2) AUTHCHALLENGE_FAIL(as_server, + require_failure_message = "We didn't originate this " + "connection"; d->c->handshake_state->started_here = 0;) AUTHCHALLENGE_FAIL(duplicate, + require_failure_message = "We already received one"; d->c->handshake_state->received_auth_challenge = 1) AUTHCHALLENGE_FAIL(nocerts, + require_failure_message = "We haven't gotten a CERTS " + "cell yet"; d->c->handshake_state->received_certs_cell = 0) AUTHCHALLENGE_FAIL(tooshort, + require_failure_message = "It was not well-formed"; d->cell->payload_len = 33) AUTHCHALLENGE_FAIL(truncated, + require_failure_message = "It was not well-formed"; d->cell->payload_len = 34) AUTHCHALLENGE_FAIL(nonzero_circid, + require_failure_message = "It had a nonzero circuit ID"; d->cell->circ_id = 1337) static tor_x509_cert_t *mock_peer_cert = NULL; @@ -650,6 +702,8 @@ authenticate_data_cleanup(const struct testcase_t *test, void *arg) authenticate_data_t *d = arg; if (d) { tor_free(d->cell); + connection_or_remove_from_identity_map(d->c1); + connection_or_remove_from_identity_map(d->c2); connection_free_(TO_CONN(d->c1)); connection_free_(TO_CONN(d->c2)); circuitmux_free(d->chan2->base_.cmux); @@ -677,6 +731,8 @@ authenticate_data_setup(const struct testcase_t *test) MOCK(channel_set_circid_type, mock_set_circid_type); d->c1 = or_connection_new(CONN_TYPE_OR, AF_INET); d->c2 = or_connection_new(CONN_TYPE_OR, AF_INET); + tor_addr_from_ipv4h(&d->c1->base_.addr, 0x01020304); + tor_addr_from_ipv4h(&d->c2->base_.addr, 0x05060708); d->key1 = pk_generate(2); d->key2 = pk_generate(3); @@ -798,57 +854,84 @@ test_link_handshake_auth_cell(void *arg) test_link_handshake_auth_ ## name(void *arg) \ { \ authenticate_data_t *d = arg; \ + const char *require_failure_message = NULL; \ + const int prev_level = setup_capture_of_logs(LOG_INFO); \ { code ; } \ tt_int_op(d->c2->handshake_state->authenticated, ==, 0); \ channel_tls_process_authenticate_cell(d->cell, d->chan2); \ tt_int_op(mock_close_called, ==, 1); \ tt_int_op(d->c2->handshake_state->authenticated, ==, 0); \ - done: \ - ; \ + if (require_failure_message) { \ + tt_assert(mock_saved_log_has_message_containing( \ + require_failure_message)); \ + } \ + done: \ + teardown_capture_of_logs(prev_level); \ } AUTHENTICATE_FAIL(badstate, + require_failure_message = "We're not doing a v3 handshake"; d->c2->base_.state = OR_CONN_STATE_CONNECTING) AUTHENTICATE_FAIL(badproto, + require_failure_message = "not using link protocol >= 3"; d->c2->link_proto = 2) AUTHENTICATE_FAIL(atclient, + require_failure_message = "We originated this connection"; d->c2->handshake_state->started_here = 1) AUTHENTICATE_FAIL(duplicate, + require_failure_message = "We already got one"; d->c2->handshake_state->received_authenticate = 1) static void test_link_handshake_auth_already_authenticated(void *arg) { authenticate_data_t *d = arg; + const int prev_level = setup_capture_of_logs(LOG_INFO); d->c2->handshake_state->authenticated = 1; channel_tls_process_authenticate_cell(d->cell, d->chan2); tt_int_op(mock_close_called, ==, 1); tt_int_op(d->c2->handshake_state->authenticated, ==, 1); + expect_log_msg_containing("The peer is already authenticated"); done: - ; + teardown_capture_of_logs(prev_level); } + AUTHENTICATE_FAIL(nocerts, + require_failure_message = "We never got a certs cell"; d->c2->handshake_state->received_certs_cell = 0) AUTHENTICATE_FAIL(noidcert, + require_failure_message = "We never got an identity " + "certificate"; tor_x509_cert_free(d->c2->handshake_state->id_cert); d->c2->handshake_state->id_cert = NULL) AUTHENTICATE_FAIL(noauthcert, + require_failure_message = "We never got an authentication " + "certificate"; tor_x509_cert_free(d->c2->handshake_state->auth_cert); d->c2->handshake_state->auth_cert = NULL) AUTHENTICATE_FAIL(tooshort, + require_failure_message = "Cell was way too short"; d->cell->payload_len = 3) AUTHENTICATE_FAIL(badtype, + require_failure_message = "Authenticator type was not " + "recognized"; d->cell->payload[0] = 0xff) AUTHENTICATE_FAIL(truncated_1, + require_failure_message = "Authenticator was truncated"; d->cell->payload[2]++) AUTHENTICATE_FAIL(truncated_2, + require_failure_message = "Authenticator was truncated"; d->cell->payload[3]++) AUTHENTICATE_FAIL(tooshort_1, + require_failure_message = "Authenticator was too short"; tt_int_op(d->cell->payload_len, >=, 260); d->cell->payload[2] -= 1; d->cell->payload_len -= 256;) AUTHENTICATE_FAIL(badcontent, + require_failure_message = "Some field in the AUTHENTICATE " + "cell body was not as expected"; d->cell->payload[10] ^= 0xff) AUTHENTICATE_FAIL(badsig_1, + require_failure_message = "Signature wasn't valid"; d->cell->payload[d->cell->payload_len - 5] ^= 0xff) #define TEST(name, flags) \ diff --git a/src/test/test_oos.c b/src/test/test_oos.c new file mode 100644 index 0000000000..db06625116 --- /dev/null +++ b/src/test/test_oos.c @@ -0,0 +1,456 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/* Unit tests for OOS handler */ + +#define CONNECTION_PRIVATE + +#include "or.h" +#include "config.h" +#include "connection.h" +#include "connection_or.h" +#include "main.h" +#include "test.h" + +static or_options_t mock_options; + +static void +reset_options_mock(void) +{ + memset(&mock_options, 0, sizeof(or_options_t)); +} + +static const or_options_t * +mock_get_options(void) +{ + return &mock_options; +} + +static int moribund_calls = 0; +static int moribund_conns = 0; + +static int +mock_connection_count_moribund(void) +{ + ++moribund_calls; + + return moribund_conns; +} + +/* + * For unit test purposes it's sufficient to tell that + * kill_conn_list_for_oos() was called with an approximately + * sane argument; it's just the thing we returned from the + * mock for pick_oos_victims(). + */ + +static int kill_conn_list_calls = 0; +static int kill_conn_list_killed = 0; + +static void +kill_conn_list_mock(smartlist_t *conns) +{ + ++kill_conn_list_calls; + + tt_assert(conns != NULL); + + kill_conn_list_killed += smartlist_len(conns); + + done: + return; +} + +static int pick_oos_mock_calls = 0; +static int pick_oos_mock_fail = 0; +static int pick_oos_mock_last_n = 0; + +static smartlist_t * +pick_oos_victims_mock(int n) +{ + smartlist_t *l = NULL; + int i; + + ++pick_oos_mock_calls; + + tt_int_op(n, OP_GT, 0); + + if (!pick_oos_mock_fail) { + /* + * connection_check_oos() just passes the list onto + * kill_conn_list_for_oos(); we don't need to simulate + * its content for this mock, just its existence, but + * we do need to check the parameter. + */ + l = smartlist_new(); + for (i = 0; i < n; ++i) smartlist_add(l, NULL); + } else { + l = NULL; + } + + pick_oos_mock_last_n = n; + + done: + return l; +} + +/** Unit test for the logic in connection_check_oos(), which is concerned + * with comparing thresholds and connection counts to decide if an OOS has + * occurred and if so, how many connections to try to kill, and then using + * pick_oos_victims() and kill_conn_list_for_oos() to carry out its grim + * duty. + */ +static void +test_oos_connection_check_oos(void *arg) +{ + (void)arg; + + /* Set up mocks */ + reset_options_mock(); + /* OOS handling is only sensitive to these fields */ + mock_options.ConnLimit = 32; + mock_options.ConnLimit_ = 64; + mock_options.ConnLimit_high_thresh = 60; + mock_options.ConnLimit_low_thresh = 50; + MOCK(get_options, mock_get_options); + moribund_calls = 0; + moribund_conns = 0; + MOCK(connection_count_moribund, mock_connection_count_moribund); + kill_conn_list_calls = 0; + kill_conn_list_killed = 0; + MOCK(kill_conn_list_for_oos, kill_conn_list_mock); + pick_oos_mock_calls = 0; + pick_oos_mock_fail = 0; + MOCK(pick_oos_victims, pick_oos_victims_mock); + + /* No OOS case */ + connection_check_oos(50, 0); + tt_int_op(moribund_calls, OP_EQ, 0); + tt_int_op(pick_oos_mock_calls, OP_EQ, 0); + tt_int_op(kill_conn_list_calls, OP_EQ, 0); + + /* OOS from socket count, nothing moribund */ + connection_check_oos(62, 0); + tt_int_op(moribund_calls, OP_EQ, 1); + tt_int_op(pick_oos_mock_calls, OP_EQ, 1); + /* 12 == 62 - ConnLimit_low_thresh */ + tt_int_op(pick_oos_mock_last_n, OP_EQ, 12); + tt_int_op(kill_conn_list_calls, OP_EQ, 1); + tt_int_op(kill_conn_list_killed, OP_EQ, 12); + + /* OOS from socket count, some are moribund */ + kill_conn_list_killed = 0; + moribund_conns = 5; + connection_check_oos(62, 0); + tt_int_op(moribund_calls, OP_EQ, 2); + tt_int_op(pick_oos_mock_calls, OP_EQ, 2); + /* 7 == 62 - ConnLimit_low_thresh - moribund_conns */ + tt_int_op(pick_oos_mock_last_n, OP_EQ, 7); + tt_int_op(kill_conn_list_calls, OP_EQ, 2); + tt_int_op(kill_conn_list_killed, OP_EQ, 7); + + /* OOS from socket count, but pick fails */ + kill_conn_list_killed = 0; + moribund_conns = 0; + pick_oos_mock_fail = 1; + connection_check_oos(62, 0); + tt_int_op(moribund_calls, OP_EQ, 3); + tt_int_op(pick_oos_mock_calls, OP_EQ, 3); + tt_int_op(kill_conn_list_calls, OP_EQ, 2); + tt_int_op(kill_conn_list_killed, OP_EQ, 0); + pick_oos_mock_fail = 0; + + /* + * OOS from socket count with so many moribund conns + * we have none to kill. + */ + kill_conn_list_killed = 0; + moribund_conns = 15; + connection_check_oos(62, 0); + tt_int_op(moribund_calls, OP_EQ, 4); + tt_int_op(pick_oos_mock_calls, OP_EQ, 3); + tt_int_op(kill_conn_list_calls, OP_EQ, 2); + + /* + * OOS from socket exhaustion; OOS handler will try to + * kill 1/10 (5) of the connections. + */ + kill_conn_list_killed = 0; + moribund_conns = 0; + connection_check_oos(50, 1); + tt_int_op(moribund_calls, OP_EQ, 5); + tt_int_op(pick_oos_mock_calls, OP_EQ, 4); + tt_int_op(kill_conn_list_calls, OP_EQ, 3); + tt_int_op(kill_conn_list_killed, OP_EQ, 5); + + /* OOS from socket exhaustion with moribund conns */ + kill_conn_list_killed = 0; + moribund_conns = 2; + connection_check_oos(50, 1); + tt_int_op(moribund_calls, OP_EQ, 6); + tt_int_op(pick_oos_mock_calls, OP_EQ, 5); + tt_int_op(kill_conn_list_calls, OP_EQ, 4); + tt_int_op(kill_conn_list_killed, OP_EQ, 3); + + /* OOS from socket exhaustion with many moribund conns */ + kill_conn_list_killed = 0; + moribund_conns = 7; + connection_check_oos(50, 1); + tt_int_op(moribund_calls, OP_EQ, 7); + tt_int_op(pick_oos_mock_calls, OP_EQ, 5); + tt_int_op(kill_conn_list_calls, OP_EQ, 4); + + /* OOS with both socket exhaustion and above-threshold */ + kill_conn_list_killed = 0; + moribund_conns = 0; + connection_check_oos(62, 1); + tt_int_op(moribund_calls, OP_EQ, 8); + tt_int_op(pick_oos_mock_calls, OP_EQ, 6); + tt_int_op(kill_conn_list_calls, OP_EQ, 5); + tt_int_op(kill_conn_list_killed, OP_EQ, 12); + + /* + * OOS with both socket exhaustion and above-threshold with some + * moribund conns + */ + kill_conn_list_killed = 0; + moribund_conns = 5; + connection_check_oos(62, 1); + tt_int_op(moribund_calls, OP_EQ, 9); + tt_int_op(pick_oos_mock_calls, OP_EQ, 7); + tt_int_op(kill_conn_list_calls, OP_EQ, 6); + tt_int_op(kill_conn_list_killed, OP_EQ, 7); + + /* + * OOS with both socket exhaustion and above-threshold with many + * moribund conns + */ + kill_conn_list_killed = 0; + moribund_conns = 15; + connection_check_oos(62, 1); + tt_int_op(moribund_calls, OP_EQ, 10); + tt_int_op(pick_oos_mock_calls, OP_EQ, 7); + tt_int_op(kill_conn_list_calls, OP_EQ, 6); + + done: + + UNMOCK(pick_oos_victims); + UNMOCK(kill_conn_list_for_oos); + UNMOCK(connection_count_moribund); + UNMOCK(get_options); + + return; +} + +static int cfe_calls = 0; + +static void +close_for_error_mock(or_connection_t *orconn, int flush) +{ + (void)flush; + + tt_assert(orconn != NULL); + ++cfe_calls; + + done: + return; +} + +static int mark_calls = 0; + +static void +mark_for_close_oos_mock(connection_t *conn, + int line, const char *file) +{ + (void)line; + (void)file; + + tt_assert(conn != NULL); + ++mark_calls; + + done: + return; +} + +static void +test_oos_kill_conn_list(void *arg) +{ + connection_t *c1, *c2; + or_connection_t *or_c1 = NULL; + dir_connection_t *dir_c2 = NULL; + smartlist_t *l = NULL; + (void)arg; + + /* Set up mocks */ + mark_calls = 0; + MOCK(connection_mark_for_close_internal_, mark_for_close_oos_mock); + cfe_calls = 0; + MOCK(connection_or_close_for_error, close_for_error_mock); + + /* Make fake conns */ + or_c1 = tor_malloc_zero(sizeof(*or_c1)); + or_c1->base_.magic = OR_CONNECTION_MAGIC; + or_c1->base_.type = CONN_TYPE_OR; + c1 = TO_CONN(or_c1); + dir_c2 = tor_malloc_zero(sizeof(*dir_c2)); + dir_c2->base_.magic = DIR_CONNECTION_MAGIC; + dir_c2->base_.type = CONN_TYPE_DIR; + dir_c2->base_.state = DIR_CONN_STATE_MIN_; + dir_c2->base_.purpose = DIR_PURPOSE_MIN_; + c2 = TO_CONN(dir_c2); + + tt_assert(c1 != NULL); + tt_assert(c2 != NULL); + + /* Make list */ + l = smartlist_new(); + smartlist_add(l, c1); + smartlist_add(l, c2); + + /* Run kill_conn_list_for_oos() */ + kill_conn_list_for_oos(l); + + /* Check call counters */ + tt_int_op(mark_calls, OP_EQ, 1); + tt_int_op(cfe_calls, OP_EQ, 1); + + done: + + UNMOCK(connection_or_close_for_error); + UNMOCK(connection_mark_for_close_internal_); + + if (l) smartlist_free(l); + tor_free(or_c1); + tor_free(dir_c2); + + return; +} + +static smartlist_t *conns_for_mock = NULL; + +static smartlist_t * +get_conns_mock(void) +{ + return conns_for_mock; +} + +/* + * For this mock, we pretend all conns have either zero or one circuits, + * depending on if this appears on the list of things to say have a circuit. + */ + +static smartlist_t *conns_with_circs = NULL; + +static int +get_num_circuits_mock(or_connection_t *conn) +{ + int circs = 0; + + tt_assert(conn != NULL); + + if (conns_with_circs && + smartlist_contains(conns_with_circs, TO_CONN(conn))) { + circs = 1; + } + + done: + return circs; +} + +static void +test_oos_pick_oos_victims(void *arg) +{ + (void)arg; + or_connection_t *ortmp; + dir_connection_t *dirtmp; + smartlist_t *picked; + + /* Set up mocks */ + conns_for_mock = smartlist_new(); + MOCK(get_connection_array, get_conns_mock); + conns_with_circs = smartlist_new(); + MOCK(connection_or_get_num_circuits, get_num_circuits_mock); + + /* Make some fake connections */ + ortmp = tor_malloc_zero(sizeof(*ortmp)); + ortmp->base_.magic = OR_CONNECTION_MAGIC; + ortmp->base_.type = CONN_TYPE_OR; + smartlist_add(conns_for_mock, TO_CONN(ortmp)); + /* We'll pretend this one has a circuit too */ + smartlist_add(conns_with_circs, TO_CONN(ortmp)); + /* Next one */ + ortmp = tor_malloc_zero(sizeof(*ortmp)); + ortmp->base_.magic = OR_CONNECTION_MAGIC; + ortmp->base_.type = CONN_TYPE_OR; + smartlist_add(conns_for_mock, TO_CONN(ortmp)); + /* Next one is moribund */ + ortmp = tor_malloc_zero(sizeof(*ortmp)); + ortmp->base_.magic = OR_CONNECTION_MAGIC; + ortmp->base_.type = CONN_TYPE_OR; + ortmp->base_.marked_for_close = 1; + smartlist_add(conns_for_mock, TO_CONN(ortmp)); + /* Last one isn't an orconn */ + dirtmp = tor_malloc_zero(sizeof(*dirtmp)); + dirtmp->base_.magic = DIR_CONNECTION_MAGIC; + dirtmp->base_.type = CONN_TYPE_DIR; + smartlist_add(conns_for_mock, TO_CONN(dirtmp)); + + /* Try picking one */ + picked = pick_oos_victims(1); + /* It should be the one with circuits */ + tt_assert(picked != NULL); + tt_int_op(smartlist_len(picked), OP_EQ, 1); + tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 0))); + smartlist_free(picked); + + /* Try picking none */ + picked = pick_oos_victims(0); + /* We should get an empty list */ + tt_assert(picked != NULL); + tt_int_op(smartlist_len(picked), OP_EQ, 0); + smartlist_free(picked); + + /* Try picking two */ + picked = pick_oos_victims(2); + /* We should get both active orconns */ + tt_assert(picked != NULL); + tt_int_op(smartlist_len(picked), OP_EQ, 2); + tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 0))); + tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 1))); + smartlist_free(picked); + + /* Try picking three - only two are eligible */ + picked = pick_oos_victims(3); + tt_int_op(smartlist_len(picked), OP_EQ, 2); + tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 0))); + tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 1))); + smartlist_free(picked); + + done: + + /* Free leftover stuff */ + if (conns_with_circs) { + smartlist_free(conns_with_circs); + conns_with_circs = NULL; + } + + UNMOCK(connection_or_get_num_circuits); + + if (conns_for_mock) { + SMARTLIST_FOREACH(conns_for_mock, connection_t *, c, tor_free(c)); + smartlist_free(conns_for_mock); + conns_for_mock = NULL; + } + + UNMOCK(get_connection_array); + + return; +} + +struct testcase_t oos_tests[] = { + { "connection_check_oos", test_oos_connection_check_oos, + TT_FORK, NULL, NULL }, + { "kill_conn_list", test_oos_kill_conn_list, TT_FORK, NULL, NULL }, + { "pick_oos_victims", test_oos_pick_oos_victims, TT_FORK, NULL, NULL }, + END_OF_TESTCASES +}; + diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index d6787e4f45..ead8d0311e 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -274,6 +274,7 @@ test_sr_commit(void *arg) time_t now = time(NULL); sr_commit_t *our_commit = NULL; smartlist_t *args = smartlist_new(); + sr_commit_t *parsed_commit = NULL; (void) arg; @@ -340,13 +341,12 @@ test_sr_commit(void *arg) /* We'll build a list of values from our commit that our parsing function * takes from a vote line and see if we can parse it correctly. */ { - sr_commit_t *parsed_commit; smartlist_add(args, tor_strdup("1")); smartlist_add(args, tor_strdup(crypto_digest_algorithm_get_name(our_commit->alg))); smartlist_add(args, tor_strdup(sr_commit_get_rsa_fpr(our_commit))); - smartlist_add(args, our_commit->encoded_commit); - smartlist_add(args, our_commit->encoded_reveal); + smartlist_add(args, tor_strdup(our_commit->encoded_commit)); + smartlist_add(args, tor_strdup(our_commit->encoded_reveal)); parsed_commit = sr_parse_commit(args); tt_assert(parsed_commit); /* That parsed commit should be _EXACTLY_ like our original commit (we @@ -354,15 +354,14 @@ test_sr_commit(void *arg) parsed_commit->valid = 1; tt_mem_op(parsed_commit, OP_EQ, our_commit, sizeof(*parsed_commit)); /* Cleanup */ - tor_free(smartlist_get(args, 0)); /* strdup here. */ - tor_free(smartlist_get(args, 1)); /* strdup here. */ - smartlist_clear(args); - sr_commit_free(parsed_commit); } done: + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); smartlist_free(args); sr_commit_free(our_commit); + sr_commit_free(parsed_commit); + authority_cert_free(auth_cert); } /* Test the encoding and decoding function for commit and reveal values. */ @@ -370,26 +369,23 @@ static void test_encoding(void *arg) { (void) arg; - int ret, duper_rand = 42; + int ret; /* Random number is 32 bytes. */ char raw_rand[32]; time_t ts = 1454333590; char hashed_rand[DIGEST256_LEN], hashed_reveal[DIGEST256_LEN]; sr_commit_t parsed_commit; - /* Encoded commit is: base64-encode( 1454333590 || H(H(42)) ). Remember - * that we do no expose the raw bytes of our PRNG to the network thus - * explaining the double H(). */ - static const char *encoded_commit = - "AAAAAFavXpZbx2LRneYFSLPCP8DLp9BXfeH5FXzbkxM4iRXKGeA54g=="; - /* Encoded reveal is: base64-encode( 1454333590 || H(42) ). */ + /* Those values were generated by sr_commit_calc_ref.py where the random + * value is 32 'A' and timestamp is the one in ts. */ static const char *encoded_reveal = - "AAAAAFavXpYk9x9kTjiQWUqjHwSAEOdPAfCaurXgjPy173SzYjeC2g=="; + "AAAAAFavXpZJxbwTupvaJCTeIUCQmOPxAMblc7ChL5H2nZKuGchdaA=="; + static const char *encoded_commit = + "AAAAAFavXpbkBMzMQG7aNoaGLFNpm2Wkk1ozXhuWWqL//GynltxVAg=="; /* Set up our raw random bytes array. */ - memset(raw_rand, 0, sizeof(raw_rand)); - memcpy(raw_rand, &duper_rand, sizeof(duper_rand)); - /* Hash random number. */ + memset(raw_rand, 'A', sizeof(raw_rand)); + /* Hash random number because we don't expose bytes of the RNG. */ ret = crypto_digest256(hashed_rand, raw_rand, sizeof(raw_rand), SR_DIGEST_ALG); tt_int_op(0, ==, ret); @@ -586,6 +582,7 @@ test_vote(void *arg) smartlist_free(tokens); smartlist_clear(args); smartlist_free(args); + tor_free(lines); } done: @@ -783,7 +780,7 @@ test_sr_setup_commits(void) tt_assert(!commit_has_reveal_value(commit_d)); done: - return; + authority_cert_free(auth_cert); } /** Verify that the SRV generation procedure is proper by testing it against @@ -970,6 +967,7 @@ test_utils(void *arg) /* Change the pubkey. */ memset(commit.rsa_identity, 0, sizeof(commit.rsa_identity)); tt_int_op(commit_is_authoritative(&commit, digest), ==, 0); + crypto_pk_free(k); } /* Testing get_phase_str(). */ @@ -1047,6 +1045,7 @@ test_state_transition(void *arg) prev = sr_state_get_previous_srv(); tt_assert(prev == cur); tt_assert(!sr_state_get_current_srv()); + sr_state_clean_srvs(); } /* New protocol run. */ @@ -1095,14 +1094,16 @@ test_keep_commit(void *arg) sr_commit_t *commit = NULL, *dup_commit = NULL; sr_state_t *state; time_t now = time(NULL); + crypto_pk_t *k = NULL; (void) arg; MOCK(trusteddirserver_get_by_v3_auth_digest, trusteddirserver_get_by_v3_auth_digest_m); - { /* Setup a minimal dirauth environment for this test */ - crypto_pk_t *k = crypto_pk_new(); + { + k = crypto_pk_new(); + /* Setup a minimal dirauth environment for this test */ /* Have a key that is not the one from our commit. */ tt_int_op(0, ==, crypto_pk_generate_key(k)); tt_int_op(0, ==, crypto_pk_get_fingerprint(k, fp, 0)); @@ -1179,6 +1180,7 @@ test_keep_commit(void *arg) done: sr_commit_free(commit); sr_commit_free(dup_commit); + crypto_pk_free(k); UNMOCK(trusteddirserver_get_by_v3_auth_digest); } diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c index 3a048fb1f0..9115823f31 100644 --- a/src/test/test_tortls.c +++ b/src/test/test_tortls.c @@ -1831,8 +1831,6 @@ test_tortls_server_info_callback(void *ignored) tls->magic = TOR_TLS_MAGIC; tls->ssl = ssl; - tor_tls_server_info_callback(NULL, 0, 0); - SSL_set_state(ssl, SSL3_ST_SW_SRVR_HELLO_A); mock_clean_saved_logs(); tor_tls_server_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 0); diff --git a/src/test/test_util.c b/src/test/test_util.c index 5432b2ccc4..3fd2dc3612 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -1723,8 +1723,7 @@ static void test_util_strmisc(void *arg) { char buf[1024]; - int i; - char *cp, *cp_tmp = NULL; + char *cp_tmp = NULL; /* Test strl operations */ (void)arg; @@ -1749,122 +1748,6 @@ test_util_strmisc(void *arg) tor_strstrip(buf, "!? "); tt_str_op(buf,OP_EQ, "Testing123"); - /* Test parse_long */ - /* Empty/zero input */ - tt_int_op(0L,OP_EQ, tor_parse_long("",10,0,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - tt_int_op(0L,OP_EQ, tor_parse_long("0",10,0,100,&i,NULL)); - tt_int_op(1,OP_EQ, i); - /* Normal cases */ - tt_int_op(10L,OP_EQ, tor_parse_long("10",10,0,100,&i,NULL)); - tt_int_op(1,OP_EQ, i); - tt_int_op(10L,OP_EQ, tor_parse_long("10",10,0,10,&i,NULL)); - tt_int_op(1,OP_EQ, i); - tt_int_op(10L,OP_EQ, tor_parse_long("10",10,10,100,&i,NULL)); - tt_int_op(1,OP_EQ, i); - tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-100,100,&i,NULL)); - tt_int_op(1,OP_EQ, i); - tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-100,0,&i,NULL)); - tt_int_op(1,OP_EQ, i); - tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-50,0,&i,NULL)); - tt_int_op(1,OP_EQ, i); - /* Extra garbage */ - tt_int_op(0L,OP_EQ, tor_parse_long("10m",10,0,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - tt_int_op(0L,OP_EQ, tor_parse_long("-50 plus garbage",10,-100,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - tt_int_op(10L,OP_EQ, tor_parse_long("10m",10,0,100,&i,&cp)); - tt_int_op(1,OP_EQ, i); - tt_str_op(cp,OP_EQ, "m"); - tt_int_op(-50L,OP_EQ, tor_parse_long("-50 plus garbage",10,-100,100,&i,&cp)); - tt_int_op(1,OP_EQ, i); - tt_str_op(cp,OP_EQ, " plus garbage"); - /* Illogical min max */ - tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,4,&i,NULL)); - tt_int_op(0,OP_EQ, i); - tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,100,-100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - /* Out of bounds */ - tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,0,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - /* Base different than 10 */ - tt_int_op(2L,OP_EQ, tor_parse_long("10",2,0,100,NULL,NULL)); - tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL)); - tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL)); - tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL)); - tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL)); - tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL)); - tt_int_op(i,OP_EQ, 0); - - /* Test parse_ulong */ - tt_int_op(0UL,OP_EQ, tor_parse_ulong("",10,0,100,NULL,NULL)); - tt_int_op(0UL,OP_EQ, tor_parse_ulong("0",10,0,100,NULL,NULL)); - tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,0,100,NULL,NULL)); - tt_int_op(0UL,OP_EQ, tor_parse_ulong("10",10,50,100,NULL,NULL)); - tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,0,10,NULL,NULL)); - tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,10,100,NULL,NULL)); - tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL)); - tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL)); - tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,-100,100,NULL,NULL)); - tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - - /* Test parse_uint64 */ - tt_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp)); - tt_int_op(1,OP_EQ, i); - tt_str_op(cp,OP_EQ, " x"); - tt_assert(U64_LITERAL(12345678901) == - tor_parse_uint64("12345678901",10,0,UINT64_MAX, &i, &cp)); - tt_int_op(1,OP_EQ, i); - tt_str_op(cp,OP_EQ, ""); - tt_assert(U64_LITERAL(0) == - tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp)); - tt_int_op(0,OP_EQ, i); - tt_assert(U64_LITERAL(0) == - tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp)); - tt_int_op(0,OP_EQ, i); - - { - /* Test parse_double */ - double d = tor_parse_double("10", 0, (double)UINT64_MAX,&i,NULL); - tt_int_op(1,OP_EQ, i); - tt_assert(DBL_TO_U64(d) == 10); - d = tor_parse_double("0", 0, (double)UINT64_MAX,&i,NULL); - tt_int_op(1,OP_EQ, i); - tt_assert(DBL_TO_U64(d) == 0); - d = tor_parse_double(" ", 0, (double)UINT64_MAX,&i,NULL); - tt_int_op(0,OP_EQ, i); - d = tor_parse_double(".0a", 0, (double)UINT64_MAX,&i,NULL); - tt_int_op(0,OP_EQ, i); - d = tor_parse_double(".0a", 0, (double)UINT64_MAX,&i,&cp); - tt_int_op(1,OP_EQ, i); - d = tor_parse_double("-.0", 0, (double)UINT64_MAX,&i,NULL); - tt_int_op(1,OP_EQ, i); - tt_assert(DBL_TO_U64(d) == 0); - d = tor_parse_double("-10", -100.0, 100.0,&i,NULL); - tt_int_op(1,OP_EQ, i); - tt_double_op(fabs(d - -10.0),OP_LT, 1E-12); - } - - { - /* Test tor_parse_* where we overflow/underflow the underlying type. */ - /* This string should overflow 64-bit ints. */ -#define TOOBIG "100000000000000000000000000" - tt_int_op(0L, OP_EQ, - tor_parse_long(TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL)); - tt_int_op(i,OP_EQ, 0); - tt_int_op(0L,OP_EQ, - tor_parse_long("-"TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL)); - tt_int_op(i,OP_EQ, 0); - tt_int_op(0UL,OP_EQ, tor_parse_ulong(TOOBIG, 10, 0, ULONG_MAX, &i, NULL)); - tt_int_op(i,OP_EQ, 0); - tt_u64_op(U64_LITERAL(0), OP_EQ, tor_parse_uint64(TOOBIG, 10, - 0, UINT64_MAX, &i, NULL)); - tt_int_op(i,OP_EQ, 0); - } - /* Test snprintf */ /* Returning -1 when there's not enough room in the output buffer */ tt_int_op(-1,OP_EQ, tor_snprintf(buf, 0, "Foo")); @@ -2054,6 +1937,144 @@ test_util_strmisc(void *arg) } static void +test_util_parse_integer(void *arg) +{ + (void)arg; + int i; + char *cp; + + /* Test parse_long */ + /* Empty/zero input */ + tt_int_op(0L,OP_EQ, tor_parse_long("",10,0,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(0L,OP_EQ, tor_parse_long("0",10,0,100,&i,NULL)); + tt_int_op(1,OP_EQ, i); + /* Normal cases */ + tt_int_op(10L,OP_EQ, tor_parse_long("10",10,0,100,&i,NULL)); + tt_int_op(1,OP_EQ, i); + tt_int_op(10L,OP_EQ, tor_parse_long("10",10,0,10,&i,NULL)); + tt_int_op(1,OP_EQ, i); + tt_int_op(10L,OP_EQ, tor_parse_long("10",10,10,100,&i,NULL)); + tt_int_op(1,OP_EQ, i); + tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-100,100,&i,NULL)); + tt_int_op(1,OP_EQ, i); + tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-100,0,&i,NULL)); + tt_int_op(1,OP_EQ, i); + tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-50,0,&i,NULL)); + tt_int_op(1,OP_EQ, i); + /* Extra garbage */ + tt_int_op(0L,OP_EQ, tor_parse_long("10m",10,0,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(0L,OP_EQ, tor_parse_long("-50 plus garbage",10,-100,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(10L,OP_EQ, tor_parse_long("10m",10,0,100,&i,&cp)); + tt_int_op(1,OP_EQ, i); + tt_str_op(cp,OP_EQ, "m"); + tt_int_op(-50L,OP_EQ, tor_parse_long("-50 plus garbage",10,-100,100,&i,&cp)); + tt_int_op(1,OP_EQ, i); + tt_str_op(cp,OP_EQ, " plus garbage"); + /* Illogical min max */ + tor_capture_bugs_(1); + tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,4,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); + tt_str_op("!(max < min)", OP_EQ, + smartlist_get(tor_get_captured_bug_log_(), 0)); + tor_end_capture_bugs_(); + tor_capture_bugs_(1); + tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,100,-100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); + tt_str_op("!(max < min)", OP_EQ, + smartlist_get(tor_get_captured_bug_log_(), 0)); + tor_end_capture_bugs_(); + /* Out of bounds */ + tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,0,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + /* Base different than 10 */ + tt_int_op(2L,OP_EQ, tor_parse_long("10",2,0,100,NULL,NULL)); + tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL)); + tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL)); + tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL)); + tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL)); + tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL)); + tt_int_op(i,OP_EQ, 0); + + /* Test parse_ulong */ + tt_int_op(0UL,OP_EQ, tor_parse_ulong("",10,0,100,NULL,NULL)); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("0",10,0,100,NULL,NULL)); + tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,0,100,NULL,NULL)); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("10",10,50,100,NULL,NULL)); + tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,0,10,NULL,NULL)); + tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,10,100,NULL,NULL)); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL)); + tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL)); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,NULL,NULL)); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + + /* Test parse_uint64 */ + tt_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp)); + tt_int_op(1,OP_EQ, i); + tt_str_op(cp,OP_EQ, " x"); + tt_assert(U64_LITERAL(12345678901) == + tor_parse_uint64("12345678901",10,0,UINT64_MAX, &i, &cp)); + tt_int_op(1,OP_EQ, i); + tt_str_op(cp,OP_EQ, ""); + tt_assert(U64_LITERAL(0) == + tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp)); + tt_int_op(0,OP_EQ, i); + tt_assert(U64_LITERAL(0) == + tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp)); + tt_int_op(0,OP_EQ, i); + + { + /* Test parse_double */ + double d = tor_parse_double("10", 0, (double)UINT64_MAX,&i,NULL); + tt_int_op(1,OP_EQ, i); + tt_assert(DBL_TO_U64(d) == 10); + d = tor_parse_double("0", 0, (double)UINT64_MAX,&i,NULL); + tt_int_op(1,OP_EQ, i); + tt_assert(DBL_TO_U64(d) == 0); + d = tor_parse_double(" ", 0, (double)UINT64_MAX,&i,NULL); + tt_int_op(0,OP_EQ, i); + d = tor_parse_double(".0a", 0, (double)UINT64_MAX,&i,NULL); + tt_int_op(0,OP_EQ, i); + d = tor_parse_double(".0a", 0, (double)UINT64_MAX,&i,&cp); + tt_int_op(1,OP_EQ, i); + d = tor_parse_double("-.0", 0, (double)UINT64_MAX,&i,NULL); + tt_int_op(1,OP_EQ, i); + tt_assert(DBL_TO_U64(d) == 0); + d = tor_parse_double("-10", -100.0, 100.0,&i,NULL); + tt_int_op(1,OP_EQ, i); + tt_double_op(fabs(d - -10.0),OP_LT, 1E-12); + } + + { + /* Test tor_parse_* where we overflow/underflow the underlying type. */ + /* This string should overflow 64-bit ints. */ +#define TOOBIG "100000000000000000000000000" + tt_int_op(0L, OP_EQ, + tor_parse_long(TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL)); + tt_int_op(i,OP_EQ, 0); + tt_int_op(0L,OP_EQ, + tor_parse_long("-"TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL)); + tt_int_op(i,OP_EQ, 0); + tt_int_op(0UL,OP_EQ, tor_parse_ulong(TOOBIG, 10, 0, ULONG_MAX, &i, NULL)); + tt_int_op(i,OP_EQ, 0); + tt_u64_op(U64_LITERAL(0), OP_EQ, tor_parse_uint64(TOOBIG, 10, + 0, UINT64_MAX, &i, NULL)); + tt_int_op(i,OP_EQ, 0); + } + done: + tor_end_capture_bugs_(); +} + +static void test_util_pow2(void *arg) { /* Test tor_log2(). */ @@ -2217,9 +2238,15 @@ test_util_gzip_compression_bomb(void *arg) tor_zlib_state_t *state = NULL; /* Make sure we can't produce a compression bomb */ + const int prev_level = setup_full_capture_of_logs(LOG_WARN); tt_int_op(-1, OP_EQ, tor_gzip_compress(&result, &result_len, one_mb, one_million, ZLIB_METHOD)); + expect_single_log_msg_containing( + "We compressed something and got an insanely high " + "compression factor; other Tors would think this " + "was a zlib bomb."); + teardown_capture_of_logs(prev_level); /* Here's a compression bomb that we made manually. */ const char compression_bomb[1039] = @@ -5254,9 +5281,11 @@ test_util_pwdb(void *arg) tt_assert(found); tor_free(dir); - prev_level = setup_capture_of_logs(LOG_ERR); /* We should do a LOG_ERR */ + /* We should do a LOG_ERR */ + prev_level = setup_full_capture_of_logs(LOG_ERR); dir = get_user_homedir(badname); tt_assert(dir == NULL); + expect_log_msg_containing("not found"); tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); teardown_capture_of_logs(prev_level); prev_level = -100; @@ -5321,6 +5350,8 @@ test_util_monotonic_time(void *arg) uint64_t nsec1, nsec2, usec1, msec1; uint64_t nsecc1, nsecc2, usecc1, msecc1; + monotime_init(); + monotime_get(&mt1); monotime_coarse_get(&mtc1); nsec1 = monotime_absolute_nsec(); @@ -5365,6 +5396,7 @@ static void test_util_monotonic_time_ratchet(void *arg) { (void)arg; + monotime_init(); monotime_reset_ratchets_for_testing(); /* win32, performance counter ratchet. */ @@ -5460,9 +5492,10 @@ struct testcase_t util_tests[] = { UTIL_LEGACY(escape_string_socks), UTIL_LEGACY(string_is_key_value), UTIL_LEGACY(strmisc), + UTIL_TEST(parse_integer, 0), UTIL_LEGACY(pow2), UTIL_LEGACY(gzip), - UTIL_LEGACY(gzip_compression_bomb), + UTIL_TEST(gzip_compression_bomb, TT_FORK), UTIL_LEGACY(datadir), UTIL_LEGACY(memarea), UTIL_LEGACY(control_formats), diff --git a/src/test/testing_common.c b/src/test/testing_common.c index ea9366305c..6460713f75 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -244,6 +244,8 @@ main(int c, const char **v) network_init(); + monotime_init(); + struct tor_libevent_cfg cfg; memset(&cfg, 0, sizeof(cfg)); tor_libevent_initialize(&cfg); @@ -272,6 +274,8 @@ main(int c, const char **v) log_severity_list_t s; 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; add_stream_log(&s, "", fileno(stdout)); } |