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