LCOV - code coverage report
Current view: top level - test - test_sendme.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 184 184 100.0 %
Date: 2021-11-24 03:28:48 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /* Copyright (c) 2014-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       4             : /* Unit tests for handling different kinds of relay cell */
       5             : 
       6             : #define CIRCUITLIST_PRIVATE
       7             : #define NETWORKSTATUS_PRIVATE
       8             : #define SENDME_PRIVATE
       9             : #define RELAY_PRIVATE
      10             : 
      11             : #include "core/or/circuit_st.h"
      12             : #include "core/or/or_circuit_st.h"
      13             : #include "core/or/origin_circuit_st.h"
      14             : #include "core/or/circuitlist.h"
      15             : #include "core/or/relay.h"
      16             : #include "core/or/sendme.h"
      17             : 
      18             : #include "feature/nodelist/networkstatus.h"
      19             : #include "feature/nodelist/networkstatus_st.h"
      20             : 
      21             : #include "lib/crypt_ops/crypto_digest.h"
      22             : 
      23             : #include "test/test.h"
      24             : #include "test/log_test_helpers.h"
      25             : 
      26             : static void
      27           1 : setup_mock_consensus(void)
      28             : {
      29           2 :   current_md_consensus = current_ns_consensus =
      30           1 :     tor_malloc_zero(sizeof(networkstatus_t));
      31           1 :   current_md_consensus->net_params = smartlist_new();
      32           1 :   current_md_consensus->routerstatus_list = smartlist_new();
      33           1 : }
      34             : 
      35             : static void
      36           1 : free_mock_consensus(void)
      37             : {
      38           1 :   SMARTLIST_FOREACH(current_md_consensus->routerstatus_list, void *, r,
      39             :                     tor_free(r));
      40           1 :   smartlist_free(current_md_consensus->routerstatus_list);
      41           1 :   smartlist_free(current_ns_consensus->net_params);
      42           1 :   tor_free(current_ns_consensus);
      43           1 : }
      44             : 
      45             : static void
      46           1 : test_v1_record_digest(void *arg)
      47             : {
      48           1 :   or_circuit_t *or_circ = NULL;
      49           1 :   circuit_t *circ = NULL;
      50             : 
      51           1 :   (void) arg;
      52             : 
      53             :   /* Create our dummy circuit. */
      54           1 :   or_circ = or_circuit_new(1, NULL);
      55             :   /* Points it to the OR circuit now. */
      56           1 :   circ = TO_CIRCUIT(or_circ);
      57             : 
      58             :   /* The package window has to be a multiple of CIRCWINDOW_INCREMENT minus 1
      59             :    * in order to catch the CIRCWINDOW_INCREMENT-nth cell. Try something that
      60             :    * shouldn't be noted. */
      61           1 :   circ->package_window = CIRCWINDOW_INCREMENT;
      62           1 :   sendme_record_cell_digest_on_circ(circ, NULL);
      63           1 :   tt_assert(!circ->sendme_last_digests);
      64             : 
      65             :   /* This should work now. Package window at CIRCWINDOW_INCREMENT + 1. */
      66           1 :   circ->package_window++;
      67           1 :   sendme_record_cell_digest_on_circ(circ, NULL);
      68           1 :   tt_assert(circ->sendme_last_digests);
      69           1 :   tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
      70             : 
      71             :   /* Next cell in the package window shouldn't do anything. */
      72           1 :   circ->package_window++;
      73           1 :   sendme_record_cell_digest_on_circ(circ, NULL);
      74           1 :   tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
      75             : 
      76             :   /* The next CIRCWINDOW_INCREMENT should add one more digest. */
      77           1 :   circ->package_window = (CIRCWINDOW_INCREMENT * 2) + 1;
      78           1 :   sendme_record_cell_digest_on_circ(circ, NULL);
      79           1 :   tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 2);
      80             : 
      81           1 :  done:
      82           1 :   circuit_free_(circ);
      83           1 : }
      84             : 
      85             : static void
      86           1 : test_v1_consensus_params(void *arg)
      87             : {
      88           1 :   (void) arg;
      89             : 
      90           1 :   setup_mock_consensus();
      91           1 :   tt_assert(current_md_consensus);
      92             : 
      93             :   /* Both zeroes. */
      94           1 :   smartlist_add(current_md_consensus->net_params,
      95             :                 (void *) "sendme_emit_min_version=0");
      96           1 :   smartlist_add(current_md_consensus->net_params,
      97             :                 (void *) "sendme_accept_min_version=0");
      98           1 :   tt_int_op(get_emit_min_version(), OP_EQ, 0);
      99           1 :   tt_int_op(get_accept_min_version(), OP_EQ, 0);
     100           1 :   smartlist_clear(current_md_consensus->net_params);
     101             : 
     102             :   /* Both ones. */
     103           1 :   smartlist_add(current_md_consensus->net_params,
     104             :                 (void *) "sendme_emit_min_version=1");
     105           1 :   smartlist_add(current_md_consensus->net_params,
     106             :                 (void *) "sendme_accept_min_version=1");
     107           1 :   tt_int_op(get_emit_min_version(), OP_EQ, 1);
     108           1 :   tt_int_op(get_accept_min_version(), OP_EQ, 1);
     109           1 :   smartlist_clear(current_md_consensus->net_params);
     110             : 
     111             :   /* Different values from each other. */
     112           1 :   smartlist_add(current_md_consensus->net_params,
     113             :                 (void *) "sendme_emit_min_version=1");
     114           1 :   smartlist_add(current_md_consensus->net_params,
     115             :                 (void *) "sendme_accept_min_version=0");
     116           1 :   tt_int_op(get_emit_min_version(), OP_EQ, 1);
     117           1 :   tt_int_op(get_accept_min_version(), OP_EQ, 0);
     118           1 :   smartlist_clear(current_md_consensus->net_params);
     119             : 
     120             :   /* Validate is the cell version is coherent with our internal default value
     121             :    * and the one in the consensus. */
     122           1 :   smartlist_add(current_md_consensus->net_params,
     123             :                 (void *) "sendme_accept_min_version=1");
     124             :   /* Minimum acceptable value is 1. */
     125           1 :   tt_int_op(cell_version_can_be_handled(1), OP_EQ, true);
     126             :   /* Minimum acceptable value is 1 so a cell version of 0 is refused. */
     127           1 :   tt_int_op(cell_version_can_be_handled(0), OP_EQ, false);
     128             : 
     129           1 :  done:
     130           1 :   free_mock_consensus();
     131           1 : }
     132             : 
     133             : static void
     134           1 : test_v1_build_cell(void *arg)
     135             : {
     136           1 :   uint8_t payload[RELAY_PAYLOAD_SIZE], digest[DIGEST_LEN];
     137           1 :   ssize_t ret;
     138           1 :   crypto_digest_t *cell_digest = NULL;
     139           1 :   or_circuit_t *or_circ = NULL;
     140           1 :   circuit_t *circ = NULL;
     141             : 
     142           1 :   (void) arg;
     143             : 
     144           1 :   or_circ = or_circuit_new(1, NULL);
     145           1 :   circ = TO_CIRCUIT(or_circ);
     146           1 :   circ->sendme_last_digests = smartlist_new();
     147             : 
     148           1 :   cell_digest = crypto_digest_new();
     149           1 :   tt_assert(cell_digest);
     150           1 :   crypto_digest_add_bytes(cell_digest, "AAAAAAAAAAAAAAAAAAAA", 20);
     151           1 :   crypto_digest_get_digest(cell_digest, (char *) digest, sizeof(digest));
     152           1 :   smartlist_add(circ->sendme_last_digests, tor_memdup(digest, sizeof(digest)));
     153             : 
     154             :   /* SENDME v1 payload is 3 bytes + 20 bytes digest. See spec. */
     155           1 :   ret = build_cell_payload_v1(digest, payload);
     156           1 :   tt_int_op(ret, OP_EQ, 23);
     157             : 
     158             :   /* Validation. */
     159             : 
     160             :   /* An empty payload means SENDME version 0 thus valid. */
     161           1 :   tt_int_op(sendme_is_valid(circ, payload, 0), OP_EQ, true);
     162             :   /* Current phoney digest should have been popped. */
     163           1 :   tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
     164             : 
     165             :   /* An unparseable cell means invalid. */
     166           1 :   setup_full_capture_of_logs(LOG_INFO);
     167           1 :   tt_int_op(sendme_is_valid(circ, (const uint8_t *) "A", 1), OP_EQ, false);
     168           1 :   expect_log_msg_containing("Unparseable SENDME cell received. "
     169           1 :                             "Closing circuit.");
     170           1 :   teardown_capture_of_logs();
     171             : 
     172             :   /* No cell digest recorded for this. */
     173           1 :   setup_full_capture_of_logs(LOG_INFO);
     174           1 :   tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, false);
     175           1 :   expect_log_msg_containing("We received a SENDME but we have no cell digests "
     176           1 :                             "to match. Closing circuit.");
     177           1 :   teardown_capture_of_logs();
     178             : 
     179             :   /* Note the wrong digest in the circuit, cell should fail validation. */
     180           1 :   circ->package_window = CIRCWINDOW_INCREMENT + 1;
     181           1 :   sendme_record_cell_digest_on_circ(circ, NULL);
     182           1 :   tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
     183           1 :   setup_full_capture_of_logs(LOG_INFO);
     184           1 :   tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, false);
     185             :   /* After a validation, the last digests is always popped out. */
     186           1 :   tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
     187           1 :   expect_log_msg_containing("SENDME v1 cell digest do not match.");
     188           1 :   teardown_capture_of_logs();
     189             : 
     190             :   /* Record the cell digest into the circuit, cell should validate. */
     191           1 :   memcpy(or_circ->crypto.sendme_digest, digest, sizeof(digest));
     192           1 :   circ->package_window = CIRCWINDOW_INCREMENT + 1;
     193           1 :   sendme_record_cell_digest_on_circ(circ, NULL);
     194           1 :   tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
     195           1 :   tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, true);
     196             :   /* After a validation, the last digests is always popped out. */
     197           1 :   tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
     198             : 
     199           1 :  done:
     200           1 :   crypto_digest_free(cell_digest);
     201           1 :   circuit_free_(circ);
     202           1 : }
     203             : 
     204             : static void
     205           1 : test_cell_payload_pad(void *arg)
     206             : {
     207           1 :   size_t pad_offset, payload_len, expected_offset;
     208             : 
     209           1 :   (void) arg;
     210             : 
     211             :   /* Offset should be 0, not enough room for padding. */
     212           1 :   payload_len = RELAY_PAYLOAD_SIZE;
     213           1 :   pad_offset = get_pad_cell_offset(payload_len);
     214           1 :   tt_int_op(pad_offset, OP_EQ, 0);
     215           1 :   tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
     216             : 
     217             :   /* Still no room because we keep 4 extra bytes. */
     218           1 :   pad_offset = get_pad_cell_offset(payload_len - 4);
     219           1 :   tt_int_op(pad_offset, OP_EQ, 0);
     220           1 :   tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
     221             : 
     222             :   /* We should have 1 byte of padding. Meaning, the offset should be the
     223             :    * CELL_PAYLOAD_SIZE minus 1 byte. */
     224           1 :   expected_offset = CELL_PAYLOAD_SIZE - 1;
     225           1 :   pad_offset = get_pad_cell_offset(payload_len - 5);
     226           1 :   tt_int_op(pad_offset, OP_EQ, expected_offset);
     227           1 :   tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
     228             : 
     229             :   /* Now some arbitrary small payload length. The cell size is header + 10 +
     230             :    * extra 4 bytes we keep so the offset should be there. */
     231           1 :   expected_offset = RELAY_HEADER_SIZE + 10 + 4;
     232           1 :   pad_offset = get_pad_cell_offset(10);
     233           1 :   tt_int_op(pad_offset, OP_EQ, expected_offset);
     234           1 :   tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
     235             : 
     236             :   /* Data length of 0. */
     237           1 :   expected_offset = RELAY_HEADER_SIZE + 4;
     238           1 :   pad_offset = get_pad_cell_offset(0);
     239           1 :   tt_int_op(pad_offset, OP_EQ, expected_offset);
     240           1 :   tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
     241             : 
     242           1 :  done:
     243           1 :   ;
     244           1 : }
     245             : 
     246             : static void
     247           1 : test_cell_version_validation(void *arg)
     248             : {
     249           1 :   (void) arg;
     250             : 
     251             :   /* We currently only support up to SENDME_MAX_SUPPORTED_VERSION so we are
     252             :    * going to test the boundaries there. */
     253             : 
     254           1 :   tt_assert(cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION));
     255             : 
     256             :   /* Version below our supported should pass. */
     257           1 :   tt_assert(cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION - 1));
     258             : 
     259             :   /* Extra version from our supported should fail. */
     260           1 :   tt_assert(!cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION + 1));
     261             : 
     262             :   /* Simple check for version 0. */
     263           1 :   tt_assert(cell_version_can_be_handled(0));
     264             : 
     265             :   /* We MUST handle the default cell version that we emit or accept. */
     266           1 :   tt_assert(cell_version_can_be_handled(SENDME_EMIT_MIN_VERSION_DEFAULT));
     267           1 :   tt_assert(cell_version_can_be_handled(SENDME_ACCEPT_MIN_VERSION_DEFAULT));
     268             : 
     269           1 :  done:
     270           1 :   ;
     271           1 : }
     272             : 
     273             : /* check our decisions about how much stuff to put into relay cells. */
     274             : static void
     275           1 : test_package_payload_len(void *arg)
     276             : {
     277           1 :   (void)arg;
     278             :   /* this is not a real circuit: it only has the fields needed for this
     279             :    * test. */
     280           1 :   circuit_t *c = tor_malloc_zero(sizeof(circuit_t));
     281             : 
     282             :   /* check initial conditions. */
     283           1 :   circuit_reset_sendme_randomness(c);
     284           1 :   tt_assert(! c->have_sent_sufficiently_random_cell);
     285           1 :   tt_int_op(c->send_randomness_after_n_cells, OP_GE, CIRCWINDOW_INCREMENT / 2);
     286           1 :   tt_int_op(c->send_randomness_after_n_cells, OP_LT, CIRCWINDOW_INCREMENT);
     287             : 
     288             :   /* We have a bunch of cells before we need to send randomness, so the first
     289             :    * few can be packaged full. */
     290           1 :   int initial = c->send_randomness_after_n_cells;
     291           1 :   size_t n = connection_edge_get_inbuf_bytes_to_package(10000, 0, c);
     292           1 :   tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n);
     293           1 :   n = connection_edge_get_inbuf_bytes_to_package(95000, 1, c);
     294           1 :   tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n);
     295           1 :   tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2);
     296             : 
     297             :   /* If package_partial isn't set, we won't package a partially full cell at
     298             :    * all. */
     299           1 :   n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 0, c);
     300           1 :   tt_int_op(n, OP_EQ, 0);
     301             :   /* no change in our state, since nothing was sent. */
     302           1 :   tt_assert(! c->have_sent_sufficiently_random_cell);
     303           1 :   tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2);
     304             : 
     305             :   /* If package_partial is set and the partial cell is not going to have
     306             :    * _enough_ randomness, we package it, but we don't consider ourselves to
     307             :    * have sent a sufficiently random cell. */
     308           1 :   n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 1, c);
     309           1 :   tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE-1);
     310           1 :   tt_assert(! c->have_sent_sufficiently_random_cell);
     311           1 :   tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 3);
     312             : 
     313             :   /* Make sure we set have_set_sufficiently_random_cell as appropriate. */
     314           1 :   n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-64, 1, c);
     315           1 :   tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE-64);
     316           1 :   tt_assert(c->have_sent_sufficiently_random_cell);
     317           1 :   tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 4);
     318             : 
     319             :   /* Now let's look at what happens when we get down to zero. Since we have
     320             :    * sent a sufficiently random cell, we will not force this one to have a gap.
     321             :    */
     322           1 :   c->send_randomness_after_n_cells = 0;
     323           1 :   n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c);
     324           1 :   tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE);
     325             :   /* Now these will be reset. */
     326           1 :   tt_assert(! c->have_sent_sufficiently_random_cell);
     327           1 :   tt_int_op(c->send_randomness_after_n_cells, OP_GE,
     328             :             CIRCWINDOW_INCREMENT / 2 - 1);
     329             : 
     330             :   /* What would happen if we hadn't sent a sufficiently random cell? */
     331           1 :   c->send_randomness_after_n_cells = 0;
     332           1 :   n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c);
     333           1 :   const size_t reduced_payload_size = RELAY_PAYLOAD_SIZE - 4 - 16;
     334           1 :   tt_int_op(n, OP_EQ, reduced_payload_size);
     335             :   /* Now these will be reset. */
     336           1 :   tt_assert(! c->have_sent_sufficiently_random_cell);
     337           1 :   tt_int_op(c->send_randomness_after_n_cells, OP_GE,
     338             :             CIRCWINDOW_INCREMENT / 2 - 1);
     339             : 
     340             :   /* Here is a fun case: if it's time to package a small cell, then
     341             :    * package_partial==0 should mean we accept that many bytes.
     342             :    */
     343           1 :   c->send_randomness_after_n_cells = 0;
     344           1 :   n = connection_edge_get_inbuf_bytes_to_package(reduced_payload_size, 0, c);
     345           1 :   tt_int_op(n, OP_EQ, reduced_payload_size);
     346             : 
     347           1 :  done:
     348           1 :   tor_free(c);
     349           1 : }
     350             : 
     351             : struct testcase_t sendme_tests[] = {
     352             :   { "v1_record_digest", test_v1_record_digest, TT_FORK,
     353             :     NULL, NULL },
     354             :   { "v1_consensus_params", test_v1_consensus_params, TT_FORK,
     355             :     NULL, NULL },
     356             :   { "v1_build_cell", test_v1_build_cell, TT_FORK,
     357             :     NULL, NULL },
     358             :   { "cell_payload_pad", test_cell_payload_pad, TT_FORK,
     359             :     NULL, NULL },
     360             :   { "cell_version_validation", test_cell_version_validation, TT_FORK,
     361             :     NULL, NULL },
     362             :   { "package_payload_len", test_package_payload_len, 0, NULL, NULL },
     363             : 
     364             :   END_OF_TESTCASES
     365             : };

Generated by: LCOV version 1.14