summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/bench.c4
-rw-r--r--src/test/include.am5
-rw-r--r--src/test/log_test_helpers.c118
-rw-r--r--src/test/log_test_helpers.h20
-rw-r--r--src/test/sr_commit_calc_ref.py51
-rw-r--r--src/test/test-memwipe.c13
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_addr.c8
-rw-r--r--src/test/test_address.c5
-rw-r--r--src/test/test_compat_libevent.c12
-rw-r--r--src/test/test_config.c2
-rw-r--r--src/test/test_crypto.c2
-rw-r--r--src/test/test_dir.c24
-rw-r--r--src/test/test_link_handshake.c105
-rw-r--r--src/test/test_oos.c456
-rw-r--r--src/test/test_shared_random.c44
-rw-r--r--src/test/test_tortls.c2
-rw-r--r--src/test/test_util.c273
-rw-r--r--src/test/testing_common.c4
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));
}