#define CIRCUITLIST_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define SENDME_PRIVATE
#define RELAY_PRIVATE
#include "core/or/circuit_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
#include "core/or/circuitlist.h"
#include "core/or/relay.h"
#include "core/or/sendme.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/networkstatus_st.h"
#include "lib/crypt_ops/crypto_digest.h"
#include "test/test.h"
#include "test/log_test_helpers.h"
static void
setup_mock_consensus(void)
{
current_md_consensus = current_ns_consensus =
tor_malloc_zero(sizeof(networkstatus_t));
current_md_consensus->net_params = smartlist_new();
current_md_consensus->routerstatus_list = smartlist_new();
}
static void
free_mock_consensus(void)
{
SMARTLIST_FOREACH(current_md_consensus->routerstatus_list, void *, r,
tor_free(r));
smartlist_free(current_md_consensus->routerstatus_list);
smartlist_free(current_ns_consensus->net_params);
tor_free(current_ns_consensus);
}
static void
test_v1_record_digest(void *arg)
{
or_circuit_t *or_circ = NULL;
circuit_t *circ = NULL;
(void) arg;
or_circ = or_circuit_new(1, NULL);
circ = TO_CIRCUIT(or_circ);
circ->package_window = CIRCWINDOW_INCREMENT;
sendme_record_cell_digest_on_circ(circ, NULL);
tt_assert(!circ->sendme_last_digests);
circ->package_window++;
sendme_record_cell_digest_on_circ(circ, NULL);
tt_assert(circ->sendme_last_digests);
tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
circ->package_window++;
sendme_record_cell_digest_on_circ(circ, NULL);
tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
circ->package_window = (CIRCWINDOW_INCREMENT * 2) + 1;
sendme_record_cell_digest_on_circ(circ, NULL);
tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 2);
done:
circuit_free_(circ);
}
static void
test_v1_consensus_params(void *arg)
{
(void) arg;
setup_mock_consensus();
tt_assert(current_md_consensus);
smartlist_add(current_md_consensus->net_params,
(void *) "sendme_emit_min_version=0");
smartlist_add(current_md_consensus->net_params,
(void *) "sendme_accept_min_version=0");
tt_int_op(get_emit_min_version(), OP_EQ, 0);
tt_int_op(get_accept_min_version(), OP_EQ, 0);
smartlist_clear(current_md_consensus->net_params);
smartlist_add(current_md_consensus->net_params,
(void *) "sendme_emit_min_version=1");
smartlist_add(current_md_consensus->net_params,
(void *) "sendme_accept_min_version=1");
tt_int_op(get_emit_min_version(), OP_EQ, 1);
tt_int_op(get_accept_min_version(), OP_EQ, 1);
smartlist_clear(current_md_consensus->net_params);
smartlist_add(current_md_consensus->net_params,
(void *) "sendme_emit_min_version=1");
smartlist_add(current_md_consensus->net_params,
(void *) "sendme_accept_min_version=0");
tt_int_op(get_emit_min_version(), OP_EQ, 1);
tt_int_op(get_accept_min_version(), OP_EQ, 0);
smartlist_clear(current_md_consensus->net_params);
smartlist_add(current_md_consensus->net_params,
(void *) "sendme_accept_min_version=1");
tt_int_op(cell_version_can_be_handled(1), OP_EQ, true);
tt_int_op(cell_version_can_be_handled(0), OP_EQ, false);
done:
free_mock_consensus();
}
static void
test_v1_build_cell(void *arg)
{
uint8_t payload[RELAY_PAYLOAD_SIZE], digest[DIGEST_LEN];
ssize_t ret;
crypto_digest_t *cell_digest = NULL;
or_circuit_t *or_circ = NULL;
circuit_t *circ = NULL;
(void) arg;
or_circ = or_circuit_new(1, NULL);
circ = TO_CIRCUIT(or_circ);
circ->sendme_last_digests = smartlist_new();
cell_digest = crypto_digest_new();
tt_assert(cell_digest);
crypto_digest_add_bytes(cell_digest, "AAAAAAAAAAAAAAAAAAAA", 20);
crypto_digest_get_digest(cell_digest, (char *) digest, sizeof(digest));
smartlist_add(circ->sendme_last_digests, tor_memdup(digest, sizeof(digest)));
ret = build_cell_payload_v1(digest, payload);
tt_int_op(ret, OP_EQ, 23);
tt_int_op(sendme_is_valid(circ, payload, 0), OP_EQ, true);
tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
setup_full_capture_of_logs(LOG_INFO);
tt_int_op(sendme_is_valid(circ, (const uint8_t *) "A", 1), OP_EQ, false);
expect_log_msg_containing("Unparseable SENDME cell received. "
"Closing circuit.");
teardown_capture_of_logs();
setup_full_capture_of_logs(LOG_INFO);
tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, false);
expect_log_msg_containing("We received a SENDME but we have no cell digests "
"to match. Closing circuit.");
teardown_capture_of_logs();
circ->package_window = CIRCWINDOW_INCREMENT + 1;
sendme_record_cell_digest_on_circ(circ, NULL);
tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
setup_full_capture_of_logs(LOG_INFO);
tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, false);
tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
expect_log_msg_containing("SENDME v1 cell digest do not match.");
teardown_capture_of_logs();
memcpy(or_circ->crypto.sendme_digest, digest, sizeof(digest));
circ->package_window = CIRCWINDOW_INCREMENT + 1;
sendme_record_cell_digest_on_circ(circ, NULL);
tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, true);
tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
done:
crypto_digest_free(cell_digest);
circuit_free_(circ);
}
static void
test_cell_payload_pad(void *arg)
{
size_t pad_offset, payload_len, expected_offset;
(void) arg;
payload_len = RELAY_PAYLOAD_SIZE;
pad_offset = get_pad_cell_offset(payload_len);
tt_int_op(pad_offset, OP_EQ, 0);
tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
pad_offset = get_pad_cell_offset(payload_len - 4);
tt_int_op(pad_offset, OP_EQ, 0);
tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
expected_offset = CELL_PAYLOAD_SIZE - 1;
pad_offset = get_pad_cell_offset(payload_len - 5);
tt_int_op(pad_offset, OP_EQ, expected_offset);
tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
expected_offset = RELAY_HEADER_SIZE + 10 + 4;
pad_offset = get_pad_cell_offset(10);
tt_int_op(pad_offset, OP_EQ, expected_offset);
tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
expected_offset = RELAY_HEADER_SIZE + 4;
pad_offset = get_pad_cell_offset(0);
tt_int_op(pad_offset, OP_EQ, expected_offset);
tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
done:
;
}
static void
test_cell_version_validation(void *arg)
{
(void) arg;
tt_assert(cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION));
tt_assert(cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION - 1));
tt_assert(!cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION + 1));
tt_assert(cell_version_can_be_handled(0));
tt_assert(cell_version_can_be_handled(SENDME_EMIT_MIN_VERSION_DEFAULT));
tt_assert(cell_version_can_be_handled(SENDME_ACCEPT_MIN_VERSION_DEFAULT));
done:
;
}
static void
test_package_payload_len(void *arg)
{
(void)arg;
circuit_t *c = tor_malloc_zero(sizeof(circuit_t));
circuit_reset_sendme_randomness(c);
tt_assert(! c->have_sent_sufficiently_random_cell);
tt_int_op(c->send_randomness_after_n_cells, OP_GE, CIRCWINDOW_INCREMENT / 2);
tt_int_op(c->send_randomness_after_n_cells, OP_LT, CIRCWINDOW_INCREMENT);
int initial = c->send_randomness_after_n_cells;
size_t n = connection_edge_get_inbuf_bytes_to_package(10000, 0, c);
tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n);
n = connection_edge_get_inbuf_bytes_to_package(95000, 1, c);
tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n);
tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2);
n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 0, c);
tt_int_op(n, OP_EQ, 0);
tt_assert(! c->have_sent_sufficiently_random_cell);
tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2);
n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 1, c);
tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE-1);
tt_assert(! c->have_sent_sufficiently_random_cell);
tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 3);
n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-64, 1, c);
tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE-64);
tt_assert(c->have_sent_sufficiently_random_cell);
tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 4);
c->send_randomness_after_n_cells = 0;
n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c);
tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE);
tt_assert(! c->have_sent_sufficiently_random_cell);
tt_int_op(c->send_randomness_after_n_cells, OP_GE,
CIRCWINDOW_INCREMENT / 2 - 1);
c->send_randomness_after_n_cells = 0;
n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c);
const size_t reduced_payload_size = RELAY_PAYLOAD_SIZE - 4 - 16;
tt_int_op(n, OP_EQ, reduced_payload_size);
tt_assert(! c->have_sent_sufficiently_random_cell);
tt_int_op(c->send_randomness_after_n_cells, OP_GE,
CIRCWINDOW_INCREMENT / 2 - 1);
c->send_randomness_after_n_cells = 0;
n = connection_edge_get_inbuf_bytes_to_package(reduced_payload_size, 0, c);
tt_int_op(n, OP_EQ, reduced_payload_size);
done:
tor_free(c);
}
struct testcase_t sendme_tests[] = {
{ "v1_record_digest", test_v1_record_digest, TT_FORK,
NULL, NULL },
{ "v1_consensus_params", test_v1_consensus_params, TT_FORK,
NULL, NULL },
{ "v1_build_cell", test_v1_build_cell, TT_FORK,
NULL, NULL },
{ "cell_payload_pad", test_cell_payload_pad, TT_FORK,
NULL, NULL },
{ "cell_version_validation", test_cell_version_validation, TT_FORK,
NULL, NULL },
{ "package_payload_len", test_package_payload_len, 0, NULL, NULL },
END_OF_TESTCASES
};