/** Update digest from the payload of cell. Assign integrity part to * cell. */ static void relay_set_digest(crypto_digest_t *digest, cell_t *cell) { char integrity[4]; relay_header_t rh; crypto_digest_add_bytes(digest, (char*)cell->payload, CELL_PAYLOAD_SIZE); crypto_digest_get_digest(digest, integrity, 4); // log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.", // integrity[0], integrity[1], integrity[2], integrity[3]); relay_header_unpack(&rh, cell->payload); memcpy(rh.integrity, integrity, 4); relay_header_pack(cell->payload, &rh); }
/** Does the digest for this circuit indicate that this cell is for us? * * Update digest from the payload of cell (with the integrity part set * to 0). If the integrity part is valid, return 1, else restore digest * and cell to their original state and return 0. */ static int relay_digest_matches(crypto_digest_t *digest, cell_t *cell) { uint32_t received_integrity, calculated_integrity; relay_header_t rh; crypto_digest_checkpoint_t backup_digest; crypto_digest_checkpoint(&backup_digest, digest); relay_header_unpack(&rh, cell->payload); memcpy(&received_integrity, rh.integrity, 4); memset(rh.integrity, 0, 4); relay_header_pack(cell->payload, &rh); // log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.", // received_integrity[0], received_integrity[1], // received_integrity[2], received_integrity[3]); crypto_digest_add_bytes(digest, (char*) cell->payload, CELL_PAYLOAD_SIZE); crypto_digest_get_digest(digest, (char*) &calculated_integrity, 4); int rv = 1; if (calculated_integrity != received_integrity) { // log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing."); // (%d vs %d).", received_integrity, calculated_integrity); /* restore digest to its old form */ crypto_digest_restore(digest, &backup_digest); /* restore the relay header */ memcpy(rh.integrity, &received_integrity, 4); relay_header_pack(cell->payload, &rh); rv = 0; } memwipe(&backup_digest, 0, sizeof(backup_digest)); return rv; }
static void make_relay_cell(cell_t *out, uint8_t command, const void *body, size_t bodylen) { relay_header_t rh; memset(&rh, 0, sizeof(rh)); rh.stream_id = 5; rh.command = command; rh.length = bodylen; out->command = CELL_RELAY; out->circ_id = 10; relay_header_pack(out->payload, &rh); memcpy(out->payload + RELAY_HEADER_SIZE, body, bodylen); }
static void test_cfmt_relay_header(void *arg) { relay_header_t rh; const uint8_t hdr_1[RELAY_HEADER_SIZE] = "\x03" "\x00\x00" "\x21\x22" "ABCD" "\x01\x03"; uint8_t hdr_out[RELAY_HEADER_SIZE]; (void)arg; tt_int_op(sizeof(hdr_1), ==, RELAY_HEADER_SIZE); relay_header_unpack(&rh, hdr_1); tt_int_op(rh.command, ==, 3); tt_int_op(rh.recognized, ==, 0); tt_int_op(rh.stream_id, ==, 0x2122); test_mem_op(rh.integrity, ==, "ABCD", 4); tt_int_op(rh.length, ==, 0x103); relay_header_pack(hdr_out, &rh); test_mem_op(hdr_out, ==, hdr_1, RELAY_HEADER_SIZE); done: ; }
static void test_circbw_relay(void *arg) { cell_t cell; relay_header_t rh; tor_addr_t addr; edge_connection_t *edgeconn; entry_connection_t *entryconn1=NULL; origin_circuit_t *circ; int delivered = 0; int overhead = 0; (void)arg; MOCK(connection_mark_unattached_ap_, mock_connection_mark_unattached_ap_); MOCK(connection_start_reading, mock_start_reading); MOCK(connection_mark_for_close_internal_, mock_mark_for_close); MOCK(relay_send_command_from_edge_, mock_send_command); MOCK(circuit_mark_for_close_, mock_mark_circ_for_close); circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0); circ->cpath->state = CPATH_STATE_AWAITING_KEYS; circ->cpath->deliver_window = CIRCWINDOW_START; entryconn1 = fake_entry_conn(circ, 1); edgeconn = ENTRY_TO_EDGE_CONN(entryconn1); /* Stream id 0: Not counted */ PACK_CELL(0, RELAY_COMMAND_END, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Stream id 1: Counted */ PACK_CELL(1, RELAY_COMMAND_END, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Properly formatted connect cell: counted */ PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234"); tor_addr_parse(&addr, "30.40.50.60"); rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE, &addr, 1024); relay_header_pack((uint8_t*)&cell.payload, &rh); \ connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Properly formatted resolved cell in correct state: counted */ edgeconn->base_.state = AP_CONN_STATE_RESOLVE_WAIT; entryconn1->socks_request->command = SOCKS_COMMAND_RESOLVE; edgeconn->on_circuit = TO_CIRCUIT(circ); PACK_CELL(1, RELAY_COMMAND_RESOLVED, "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); edgeconn->base_.state = AP_CONN_STATE_OPEN; entryconn1->socks_request->has_finished = 1; /* Connected cell after open: not counted */ PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Resolved cell after open: not counted */ PACK_CELL(1, RELAY_COMMAND_RESOLVED, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Drop cell: not counted */ PACK_CELL(1, RELAY_COMMAND_DROP, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Data cell on stream 0: not counted */ PACK_CELL(0, RELAY_COMMAND_DATA, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Data cell on open connection: counted */ ENTRY_TO_CONN(entryconn1)->marked_for_close = 0; PACK_CELL(1, RELAY_COMMAND_DATA, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Empty Data cell on open connection: not counted */ ENTRY_TO_CONN(entryconn1)->marked_for_close = 0; PACK_CELL(1, RELAY_COMMAND_DATA, ""); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on valid stream: counted */ edgeconn->package_window -= STREAMWINDOW_INCREMENT; ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Sendme on valid stream with full window: not counted */ ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); edgeconn->package_window = STREAMWINDOW_START; connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on unknown stream: not counted */ ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on circuit with full window: not counted */ PACK_CELL(0, RELAY_COMMAND_SENDME, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on circuit with non-full window: counted */ PACK_CELL(0, RELAY_COMMAND_SENDME, "Data1234"); circ->cpath->package_window = 900; connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Invalid extended cell: not counted */ PACK_CELL(1, RELAY_COMMAND_EXTENDED2, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Invalid extended cell: not counted */ PACK_CELL(1, RELAY_COMMAND_EXTENDED, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Invalid HS cell: not counted */ PACK_CELL(1, RELAY_COMMAND_ESTABLISH_INTRO, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* "Valid" HS cell in expected state: counted */ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND; PACK_CELL(1, RELAY_COMMAND_RENDEZVOUS_ESTABLISHED, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); /* End cell on non-closed connection: counted */ PACK_CELL(1, RELAY_COMMAND_END, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* End cell on connection that already got one: not counted */ PACK_CELL(1, RELAY_COMMAND_END, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Simulate closed stream on entryconn, then test: */ if (!subtest_circbw_halfclosed(circ, 2)) goto done; circ->base_.purpose = CIRCUIT_PURPOSE_PATH_BIAS_TESTING; if (!subtest_circbw_halfclosed(circ, 6)) goto done; /* Path bias: truncated */ tt_int_op(circ->base_.marked_for_close, OP_EQ, 0); PACK_CELL(0, RELAY_COMMAND_TRUNCATED, "Data1234"); pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); tt_int_op(circ->base_.marked_for_close, OP_EQ, 1); done: UNMOCK(connection_start_reading); UNMOCK(connection_mark_unattached_ap_); UNMOCK(connection_mark_for_close_internal_); UNMOCK(relay_send_command_from_edge_); UNMOCK(circuit_mark_for_close_); circuit_free_(TO_CIRCUIT(circ)); connection_free_minimal(ENTRY_TO_CONN(entryconn1)); }