tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

commit 79ae64f1e91bb3d291a2fa6312622e52a0bd6dd4
parent 9e16924a7c79d928ff1b075b0105ec3c73cd0040
Author: Nick Mathewson <nickm@torproject.org>
Date:   Tue,  6 May 2025 12:29:13 -0400

Merge branch '41051_cell_format' into 'main'

Prop359: Add functions to encode/decode new relay message format for CGO

Closes #41051 and #41056

See merge request tpo/core/tor!878
Diffstat:
Achanges/bug41056 | 4++++
Achanges/ticket41051 | 5+++++
Msrc/app/main/main.c | 5+++--
Msrc/core/crypto/relay_crypto.c | 61+++++++++++++++++++++++++++++++++++--------------------------
Msrc/core/crypto/relay_crypto.h | 3+--
Msrc/core/mainloop/connection.c | 4++--
Msrc/core/mainloop/cpuworker.c | 3+++
Msrc/core/or/circuitbuild.c | 8+++++++-
Msrc/core/or/circuitpadding.c | 25+++++++++++--------------
Msrc/core/or/circuitpadding.h | 10+++++-----
Msrc/core/or/circuituse.c | 12+++++++-----
Msrc/core/or/command.c | 7++++++-
Msrc/core/or/conflux.c | 59+++++++++++++++++++++++++++++++++++++----------------------
Msrc/core/or/conflux.h | 25++++++++++++++-----------
Msrc/core/or/conflux_cell.c | 50++++++++++++++++++++++++--------------------------
Msrc/core/or/conflux_cell.h | 10++++------
Msrc/core/or/conflux_pool.c | 16+++++++---------
Msrc/core/or/conflux_pool.h | 6+++---
Msrc/core/or/congestion_control_flow.c | 21++++++++++-----------
Msrc/core/or/congestion_control_flow.h | 7++++---
Msrc/core/or/connection_edge.c | 92++++++++++++++++++++++++++++++++++---------------------------------------------
Msrc/core/or/connection_edge.h | 10++++++----
Msrc/core/or/crypt_path.c | 5++++-
Msrc/core/or/crypt_path_st.h | 3+++
Msrc/core/or/include.am | 3+++
Msrc/core/or/onion.c | 28++++++++++++++++------------
Msrc/core/or/onion.h | 7+++++--
Msrc/core/or/or.h | 98++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/core/or/or_circuit_st.h | 4++++
Msrc/core/or/relay.c | 519++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/core/or/relay.h | 37++++++++++++++++++++++++-------------
Asrc/core/or/relay_msg.c | 286+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/or/relay_msg.h | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/or/relay_msg_st.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
Msrc/core/or/sendme.c | 6+++---
Msrc/core/or/status.c | 3++-
Msrc/feature/client/circpathbias.c | 62+++++++++++++++++++++++++++-----------------------------------
Msrc/feature/client/circpathbias.h | 6++++--
Msrc/feature/hs/hs_cell.c | 21++++++++++++---------
Msrc/feature/hs/hs_circuit.c | 11+++++++----
Msrc/feature/relay/circuitbuild_relay.c | 13++++---------
Msrc/feature/relay/circuitbuild_relay.h | 7++++---
Msrc/feature/relay/dns.c | 10+++++++---
Msrc/test/test_cell_formats.c | 741+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/test/test_circuitbuild.c | 31++++++++++++++++++-------------
Msrc/test/test_circuitpadding.c | 47++++++++++++++++++++++++++++++-----------------
Msrc/test/test_conflux_cell.c | 17+++++++++++------
Msrc/test/test_conflux_pool.c | 15+++++++++++----
Msrc/test/test_relaycell.c | 229+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/test/test_sendme.c | 75+++++++++++++++++++--------------------------------------------------------
50 files changed, 1906 insertions(+), 956 deletions(-)

diff --git a/changes/bug41056 b/changes/bug41056 @@ -0,0 +1,4 @@ + o Minor bugfixes (protocol): + - Set the length field correctly on RELAY_COMMAND_CONFLUX_SWITCH + messages. Previously, it was always set to the maximum value. + Fixes bug 41056; bugfix on 0.4.8.1-alpha. diff --git a/changes/ticket41051 b/changes/ticket41051 @@ -0,0 +1,5 @@ + o Major features (cell format): + - Tor now has (unused) internal support to encode and decode + relay messages in the new format required by our newer + CGO encryption algorithm. + Closes ticket 41051. Part of proposal 359. diff --git a/src/app/main/main.c b/src/app/main/main.c @@ -377,6 +377,7 @@ dumpstats(int severity) channel_dumpstats(severity); channel_listener_dumpstats(severity); + // TODO CGO: Use of RELAY_PAYLOAD_SIZE_MAX may make this a bit wrong. tor_log(severity, LD_NET, "Cells processed: %"PRIu64" padding\n" " %"PRIu64" create\n" @@ -395,11 +396,11 @@ dumpstats(int severity) if (stats_n_data_cells_packaged) tor_log(severity,LD_NET,"Average packaged cell fullness: %2.3f%%", 100*(((double)stats_n_data_bytes_packaged) / - ((double)stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) ); + ((double)stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE_MAX)) ); if (stats_n_data_cells_received) tor_log(severity,LD_NET,"Average delivered cell fullness: %2.3f%%", 100*(((double)stats_n_data_bytes_received) / - ((double)stats_n_data_cells_received*RELAY_PAYLOAD_SIZE)) ); + ((double)stats_n_data_cells_received*RELAY_PAYLOAD_SIZE_MAX)) ); cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_TAP, "TAP"); cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_NTOR,"ntor"); diff --git a/src/core/crypto/relay_crypto.c b/src/core/crypto/relay_crypto.c @@ -19,27 +19,33 @@ #include "core/or/relay.h" #include "core/crypto/relay_crypto.h" #include "core/or/sendme.h" +#include "lib/cc/ctassert.h" #include "core/or/cell_st.h" #include "core/or/or_circuit_st.h" #include "core/or/origin_circuit_st.h" -/** Update digest from the payload of cell. Assign integrity part to +/* TODO CGO: This file will be largely incorrect when we have + * CGO crypto. */ + +/* Offset of digest within relay cell body for v0 cells. */ +#define V0_DIGEST_OFFSET 5 +#define V0_DIGEST_LEN 4 +#define V0_RECOGNIZED_OFFSET 1 + +/** Update digest{ from the payload of cell. Assign integrity part to * cell. */ void -relay_set_digest(crypto_digest_t *digest, cell_t *cell) +relay_set_digest_v0(crypto_digest_t *digest, cell_t *cell) { - char integrity[4]; - relay_header_t rh; + char integrity[V0_DIGEST_LEN]; crypto_digest_add_bytes(digest, (char*)cell->payload, CELL_PAYLOAD_SIZE); - crypto_digest_get_digest(digest, integrity, 4); + crypto_digest_get_digest(digest, integrity, V0_DIGEST_LEN); // 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); + memcpy(cell->payload + V0_DIGEST_OFFSET, integrity, V0_DIGEST_LEN); } /** Does the digest for this circuit indicate that this cell is for us? @@ -49,25 +55,25 @@ relay_set_digest(crypto_digest_t *digest, cell_t *cell) * and cell to their original state and return 0. */ static int -relay_digest_matches(crypto_digest_t *digest, cell_t *cell) +relay_digest_matches_v0(crypto_digest_t *digest, cell_t *cell) { uint32_t received_integrity, calculated_integrity; - relay_header_t rh; crypto_digest_checkpoint_t backup_digest; + CTASSERT(sizeof(uint32_t) == V0_DIGEST_LEN); + 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); + memcpy(&received_integrity, cell->payload + V0_DIGEST_OFFSET, V0_DIGEST_LEN); + memset(cell->payload + V0_DIGEST_OFFSET, 0, V0_DIGEST_LEN); // 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); + crypto_digest_get_digest(digest, (char*) &calculated_integrity, + V0_DIGEST_LEN); int rv = 1; @@ -77,8 +83,8 @@ relay_digest_matches(crypto_digest_t *digest, cell_t *cell) /* 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); + memcpy(cell->payload + V0_DIGEST_OFFSET, &received_integrity, + V0_DIGEST_LEN); rv = 0; } @@ -86,6 +92,12 @@ relay_digest_matches(crypto_digest_t *digest, cell_t *cell) return rv; } +static inline bool +relay_cell_is_recognized_v0(const cell_t *cell) +{ + return get_uint16(cell->payload + V0_RECOGNIZED_OFFSET) == 0; +} + /** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b> * (in place). * @@ -146,8 +158,6 @@ relay_decrypt_cell(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, crypt_path_t **layer_hint, char *recognized) { - relay_header_t rh; - tor_assert(circ); tor_assert(cell); tor_assert(recognized); @@ -170,10 +180,10 @@ relay_decrypt_cell(circuit_t *circ, cell_t *cell, /* decrypt one layer */ cpath_crypt_cell(thishop, cell->payload, true); - relay_header_unpack(&rh, cell->payload); - if (rh.recognized == 0) { + if (relay_cell_is_recognized_v0(cell)) { /* it's possibly recognized. have to check digest to be sure. */ - if (relay_digest_matches(cpath_get_incoming_digest(thishop), cell)) { + if (relay_digest_matches_v0(cpath_get_incoming_digest(thishop), + cell)) { *recognized = 1; *layer_hint = thishop; return 0; @@ -196,10 +206,9 @@ relay_decrypt_cell(circuit_t *circ, cell_t *cell, relay_crypt_one_payload(crypto->f_crypto, cell->payload); - relay_header_unpack(&rh, cell->payload); - if (rh.recognized == 0) { + if (relay_cell_is_recognized_v0(cell)) { /* it's possibly recognized. have to check digest to be sure. */ - if (relay_digest_matches(crypto->f_digest, cell)) { + if (relay_digest_matches_v0(crypto->f_digest, cell)) { *recognized = 1; return 0; } @@ -248,7 +257,7 @@ void relay_encrypt_cell_inbound(cell_t *cell, or_circuit_t *or_circ) { - relay_set_digest(or_circ->crypto.b_digest, cell); + relay_set_digest_v0(or_circ->crypto.b_digest, cell); /* Record cell digest as the SENDME digest if need be. */ sendme_record_sending_cell_digest(TO_CIRCUIT(or_circ), NULL); diff --git a/src/core/crypto/relay_crypto.h b/src/core/crypto/relay_crypto.h @@ -36,7 +36,6 @@ void relay_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in); void -relay_set_digest(crypto_digest_t *digest, cell_t *cell); +relay_set_digest_v0(crypto_digest_t *digest, cell_t *cell); #endif /* !defined(TOR_RELAY_CRYPTO_H) */ - diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c @@ -3481,7 +3481,7 @@ connection_bucket_get_share(int base, int priority, static ssize_t connection_bucket_read_limit(connection_t *conn, time_t now) { - int base = RELAY_PAYLOAD_SIZE; + int base = RELAY_PAYLOAD_SIZE_MAX; int priority = conn->type != CONN_TYPE_DIR; ssize_t conn_bucket = -1; size_t global_bucket_val = token_bucket_rw_get_read(&global_bucket); @@ -3535,7 +3535,7 @@ connection_bucket_read_limit(connection_t *conn, time_t now) ssize_t connection_bucket_write_limit(connection_t *conn, time_t now) { - int base = RELAY_PAYLOAD_SIZE; + int base = RELAY_PAYLOAD_SIZE_MAX; int priority = conn->type != CONN_TYPE_DIR; size_t conn_bucket = buf_datalen(conn->outbuf); size_t global_bucket_val = token_bucket_rw_get_write(&global_bucket); diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c @@ -451,6 +451,9 @@ cpuworker_onion_handshake_replyfn(void *work_) } } + // TODO CGO: Initialize this from a real handshake. + circ->relay_cell_format = RELAY_CELL_FORMAT_V0; + if (onionskin_answer(circ, &rpl.created_cell, (const char*)rpl.keys, sizeof(rpl.keys), diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c @@ -1185,12 +1185,18 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ, { uint8_t command = 0; uint16_t payload_len=0; - uint8_t payload[RELAY_PAYLOAD_SIZE]; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX]; if (extend_cell_format(&command, &payload_len, payload, &ec)<0) { log_warn(LD_CIRC,"Couldn't format extend cell"); return -END_CIRC_REASON_INTERNAL; } + if (payload_len > circuit_max_relay_payload( + TO_CIRCUIT(circ), hop->prev, command)) { + log_warn(LD_BUG, "Generated a too-long extend cell"); + return -END_CIRC_REASON_INTERNAL; + } + /* send it to hop->prev, because that relay will transfer * it to a create cell and then send to hop */ if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c @@ -1846,22 +1846,21 @@ circpad_cell_event_nonpadding_sent(circuit_t *on_circ) * not need any other consideration, otherwise return 1. */ int -circpad_check_received_cell(cell_t *cell, circuit_t *circ, - crypt_path_t *layer_hint, - const relay_header_t *rh) +circpad_check_received_cell(const relay_msg_t *msg, circuit_t *circ, + crypt_path_t *layer_hint) { /* First handle the padding commands, since we want to ignore any other * commands if this circuit is padding-specific. */ - switch (rh->command) { + switch (msg->command) { case RELAY_COMMAND_DROP: /* Already examined in circpad_deliver_recognized_relay_cell_events */ return 0; case RELAY_COMMAND_PADDING_NEGOTIATE: - circpad_handle_padding_negotiate(circ, cell); + circpad_handle_padding_negotiate(circ, msg); return 0; case RELAY_COMMAND_PADDING_NEGOTIATED: - if (circpad_handle_padding_negotiated(circ, cell, layer_hint) == 0) - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + if (circpad_handle_padding_negotiated(circ, msg, layer_hint) == 0) + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); return 0; } @@ -1888,7 +1887,7 @@ circpad_check_received_cell(cell_t *cell, circuit_t *circ, if (circ->purpose == CIRCUIT_PURPOSE_C_CIRCUIT_PADDING) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, "Ignored cell (%d) that arrived in padding circuit " - " %u.", rh->command, CIRCUIT_IS_ORIGIN(circ) ? + " %u.", msg->command, CIRCUIT_IS_ORIGIN(circ) ? TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0); return 0; } @@ -2969,7 +2968,7 @@ circpad_padding_negotiated(circuit_t *circ, * Returns -1 on error, 0 on success. */ signed_error_t -circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) +circpad_handle_padding_negotiate(circuit_t *circ, const relay_msg_t *msg) { int retval = 0; /* Should we send back a STOP cell? */ @@ -2983,8 +2982,7 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) return -1; } - if (circpad_negotiate_parse(&negotiate, cell->payload+RELAY_HEADER_SIZE, - CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) { + if (circpad_negotiate_parse(&negotiate, msg->body, msg->length) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, "Received malformed PADDING_NEGOTIATE cell; dropping."); return -1; @@ -3057,7 +3055,7 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) * Returns -1 on error, 0 on success. */ signed_error_t -circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell, +circpad_handle_padding_negotiated(circuit_t *circ, const relay_msg_t *msg, crypt_path_t *layer_hint) { circpad_negotiated_t *negotiated; @@ -3076,8 +3074,7 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell, return -1; } - if (circpad_negotiated_parse(&negotiated, cell->payload+RELAY_HEADER_SIZE, - CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) { + if (circpad_negotiated_parse(&negotiated, msg->body, msg->length) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, "Received malformed PADDING_NEGOTIATED cell on circuit %u; " "dropping.", TO_ORIGIN_CIRCUIT(circ)->global_identifier); diff --git a/src/core/or/circuitpadding.h b/src/core/or/circuitpadding.h @@ -12,6 +12,7 @@ #include "trunnel/circpad_negotiation.h" #include "lib/evloop/timers.h" +#include "core/or/relay_msg_st.h" struct circuit_t; struct origin_circuit_t; @@ -736,9 +737,9 @@ const circpad_machine_spec_t *circpad_string_to_machine(const char *str); /* Padding negotiation between client and middle */ signed_error_t circpad_handle_padding_negotiate(struct circuit_t *circ, - struct cell_t *cell); + const relay_msg_t *msg); signed_error_t circpad_handle_padding_negotiated(struct circuit_t *circ, - struct cell_t *cell, + const relay_msg_t *msg, crypt_path_t *layer_hint); signed_error_t circpad_negotiate_padding(struct origin_circuit_t *circ, circpad_machine_num_t machine, @@ -753,9 +754,8 @@ bool circpad_padding_negotiated(struct circuit_t *circ, circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose); -int circpad_check_received_cell(cell_t *cell, circuit_t *circ, - crypt_path_t *layer_hint, - const relay_header_t *rh); +int circpad_check_received_cell(const relay_msg_t *msg, circuit_t *circ, + crypt_path_t *layer_hint); MOCK_DECL(circpad_decision_t, circpad_machine_schedule_padding,(circpad_machine_runtime_t *)); diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c @@ -3181,15 +3181,16 @@ circuit_sent_valid_data(origin_circuit_t *circ, uint16_t relay_body_len) { if (!circ) return; - tor_assertf_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE, + tor_assertf_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE_MAX, "Wrong relay_body_len: %d (should be at most %d)", - relay_body_len, RELAY_PAYLOAD_SIZE); + relay_body_len, RELAY_PAYLOAD_SIZE_MAX); circ->n_delivered_written_circ_bw = tor_add_u32_nowrap(circ->n_delivered_written_circ_bw, relay_body_len); + // TODO CGO: I think this may now be somewhat incorrect. circ->n_overhead_written_circ_bw = tor_add_u32_nowrap(circ->n_overhead_written_circ_bw, - RELAY_PAYLOAD_SIZE-relay_body_len); + RELAY_PAYLOAD_SIZE_MAX-relay_body_len); } /** @@ -3202,11 +3203,12 @@ circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len) { if (!circ) return; - tor_assert_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE); + tor_assert_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE_MAX); circ->n_delivered_read_circ_bw = tor_add_u32_nowrap(circ->n_delivered_read_circ_bw, relay_body_len); + // TODO CGO: I think this may now be somewhat incorrect. circ->n_overhead_read_circ_bw = tor_add_u32_nowrap(circ->n_overhead_read_circ_bw, - RELAY_PAYLOAD_SIZE-relay_body_len); + RELAY_PAYLOAD_SIZE_MAX-relay_body_len); } diff --git a/src/core/or/command.c b/src/core/or/command.c @@ -456,7 +456,7 @@ command_process_created_cell(cell_t *cell, channel_t *chan) } else { /* pack it into an extended relay cell, and send it. */ uint8_t command=0; uint16_t len=0; - uint8_t payload[RELAY_PAYLOAD_SIZE]; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX]; log_debug(LD_OR, "Converting created cell to extended relay cell, sending."); memset(payload, 0, sizeof(payload)); @@ -469,6 +469,11 @@ command_process_created_cell(cell_t *cell, channel_t *chan) circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); return; } + if (len > circuit_max_relay_payload(circ, NULL, command)) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, "Created cell too big to package."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + return; + } relay_send_command_from_edge(0, circ, command, (const char*)payload, len, NULL); diff --git a/src/core/or/conflux.c b/src/core/or/conflux.c @@ -6,6 +6,7 @@ * \brief Conflux multipath core algorithms */ +#include "core/or/relay_msg.h" #define TOR_CONFLUX_PRIVATE #include "core/or/or.h" @@ -169,7 +170,7 @@ uint64_t conflux_get_circ_bytes_allocation(const circuit_t *circ) { if (circ->conflux) { - return smartlist_len(circ->conflux->ooo_q) * sizeof(conflux_cell_t); + return smartlist_len(circ->conflux->ooo_q) * sizeof(conflux_msg_t); } return 0; } @@ -680,8 +681,8 @@ conflux_queue_cmp(const void *a, const void *b) { // Compare a and b as conflux_cell_t using the seq field, and return a // comparison result such that the lowest seq is at the head of the pqueue. - const conflux_cell_t *cell_a = a; - const conflux_cell_t *cell_b = b; + const conflux_msg_t *cell_a = a; + const conflux_msg_t *cell_b = b; tor_assert(cell_a); tor_assert(cell_b); @@ -732,12 +733,11 @@ circuit_ccontrol(const circuit_t *circ) */ int conflux_process_switch_command(circuit_t *in_circ, - crypt_path_t *layer_hint, cell_t *cell, - relay_header_t *rh) + crypt_path_t *layer_hint, + const relay_msg_t *msg) { tor_assert(in_circ); - tor_assert(cell); - tor_assert(rh); + tor_assert(msg); conflux_t *cfx = in_circ->conflux; uint32_t relative_seq; @@ -781,7 +781,7 @@ conflux_process_switch_command(circuit_t *in_circ, return -1; } - relative_seq = conflux_cell_parse_switch(cell, rh->length); + relative_seq = conflux_cell_parse_switch(msg); /* * We have to make sure that the switch command is truely @@ -816,7 +816,7 @@ conflux_process_switch_command(circuit_t *in_circ, /* Mark this data as validated for controlport and vanguards * dropped cell handling */ if (CIRCUIT_IS_ORIGIN(in_circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(in_circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(in_circ), msg->length); } return 0; @@ -830,8 +830,8 @@ conflux_process_switch_command(circuit_t *in_circ, * to streams, false otherwise. */ bool -conflux_process_cell(conflux_t *cfx, circuit_t *in_circ, - crypt_path_t *layer_hint, cell_t *cell) +conflux_process_relay_msg(conflux_t *cfx, circuit_t *in_circ, + crypt_path_t *layer_hint, const relay_msg_t *msg) { // TODO-329-TUNING: Temporarily validate legs here. We can remove // this after tuning is complete. @@ -867,14 +867,19 @@ conflux_process_cell(conflux_t *cfx, circuit_t *in_circ, circuit_mark_for_close(in_circ, END_CIRC_REASON_INTERNAL); return false; } else { - conflux_cell_t *c_cell = tor_malloc_zero(sizeof(conflux_cell_t)); - c_cell->seq = leg->last_seq_recv; - - memcpy(&c_cell->cell, cell, sizeof(cell_t)); + conflux_msg_t *c_msg = tor_malloc_zero(sizeof(conflux_msg_t)); + c_msg->seq = leg->last_seq_recv; + /* Notice the copy here. Reason is that we don't have ownership of the + * message. If we wanted to pull that off, we would need to change the + * whole calling stack and unit tests on either not touching it after this + * function indicates that it has taken it or never allocate it from the + * stack. This is simpler and less error prone but might show up in our + * profile (maybe?). The Maze is serious. It needs to be respected. */ + c_msg->msg = relay_msg_copy(msg); smartlist_pqueue_add(cfx->ooo_q, conflux_queue_cmp, - offsetof(conflux_cell_t, heap_idx), c_cell); - total_ooo_q_bytes += sizeof(cell_t); + offsetof(conflux_msg_t, heap_idx), c_msg); + total_ooo_q_bytes += sizeof(msg->length); /* This cell should not be processed yet, and the queue is not ready * to process because the next absolute seqnum has not yet arrived */ @@ -888,10 +893,10 @@ conflux_process_cell(conflux_t *cfx, circuit_t *in_circ, * Returns the cell as a conflux_cell_t, or NULL if the queue is empty * or has a hole. */ -conflux_cell_t * -conflux_dequeue_cell(conflux_t *cfx) +conflux_msg_t * +conflux_dequeue_relay_msg(conflux_t *cfx) { - conflux_cell_t *top = NULL; + conflux_msg_t *top = NULL; if (smartlist_len(cfx->ooo_q) == 0) return NULL; @@ -901,11 +906,21 @@ conflux_dequeue_cell(conflux_t *cfx) * pop and return it. */ if (top->seq == cfx->last_seq_delivered+1) { smartlist_pqueue_pop(cfx->ooo_q, conflux_queue_cmp, - offsetof(conflux_cell_t, heap_idx)); - total_ooo_q_bytes -= sizeof(cell_t); + offsetof(conflux_msg_t, heap_idx)); + total_ooo_q_bytes -= sizeof(top->msg->length); cfx->last_seq_delivered++; return top; } else { return NULL; } } + +/** Free a given conflux msg object. */ +void +conflux_relay_msg_free_(conflux_msg_t *msg) +{ + if (msg) { + relay_msg_free(msg->msg); + tor_free(msg); + } +} diff --git a/src/core/or/conflux.h b/src/core/or/conflux.h @@ -11,6 +11,7 @@ #include "core/or/circuit_st.h" #include "core/or/conflux_st.h" +#include "core/or/relay_msg_st.h" typedef struct conflux_t conflux_t; typedef struct conflux_leg_t conflux_leg_t; @@ -24,8 +25,7 @@ typedef struct conflux_leg_t conflux_leg_t; /** Helper: Return the number of legs a conflux object has. */ #define CONFLUX_NUM_LEGS(cfx) (smartlist_len(cfx->legs)) -/** A cell for the out-of-order queue. - * XXX: Consider trying to use packed_cell_t instead here? */ +/** A relay message for the out-of-order queue. */ typedef struct { /** * Absolute sequence number of this cell, computed from the @@ -37,10 +37,10 @@ typedef struct { */ int heap_idx; - /** The cell here is always guaranteed to have removed its + /** The relay message here is always guaranteed to have removed its * extra conflux sequence number, for ease of processing */ - cell_t cell; -} conflux_cell_t; + relay_msg_t *msg; +} conflux_msg_t; size_t conflux_handle_oom(size_t bytes_to_remove); uint64_t conflux_get_total_bytes_allocation(void); @@ -54,15 +54,18 @@ circuit_t *conflux_decide_circ_for_send(conflux_t *cfx, circuit_t *conflux_decide_next_circ(conflux_t *cfx); int conflux_process_switch_command(circuit_t *in_circ, - crypt_path_t *layer_hint, cell_t *cell, - relay_header_t *rh); + crypt_path_t *layer_hint, + const relay_msg_t *msg); bool conflux_should_multiplex(int relay_command); -bool conflux_process_cell(conflux_t *cfx, circuit_t *in_circ, - crypt_path_t *layer_hint, - cell_t *cell); -conflux_cell_t *conflux_dequeue_cell(conflux_t *cfx); +bool conflux_process_relay_msg(conflux_t *cfx, circuit_t *in_circ, + crypt_path_t *layer_hint, + const relay_msg_t *msg); +conflux_msg_t *conflux_dequeue_relay_msg(conflux_t *cfx); void conflux_note_cell_sent(conflux_t *cfx, circuit_t *circ, uint8_t relay_command); +void conflux_relay_msg_free_(conflux_msg_t *msg); +#define conflux_relay_msg_free(msg) \ + FREE_AND_NULL(conflux_msg_t, conflux_relay_msg_free_, (msg)) /* Private section starts. */ #ifdef TOR_CONFLUX_PRIVATE diff --git a/src/core/or/conflux_cell.c b/src/core/or/conflux_cell.c @@ -63,7 +63,8 @@ build_link_cell(const conflux_cell_link_t *link, uint8_t *cell_out) trn_cell_conflux_link_getlen_payload(cell), payload); /* Encode cell. */ - cell_len = trn_cell_conflux_link_encode(cell_out, RELAY_PAYLOAD_SIZE, cell); + cell_len = trn_cell_conflux_link_encode(cell_out, + RELAY_PAYLOAD_SIZE_MAX, cell); trn_cell_conflux_link_payload_v1_free(payload); trn_cell_conflux_link_free(cell); @@ -87,7 +88,8 @@ build_linked_ack_cell(uint8_t *cell_out) tor_assert(cell_out); cell = trn_cell_conflux_linked_ack_new(); - cell_len = trn_cell_conflux_linked_ack_encode(cell_out, RELAY_PAYLOAD_SIZE, + cell_len = trn_cell_conflux_linked_ack_encode(cell_out, + RELAY_PAYLOAD_SIZE_MAX, cell); trn_cell_conflux_linked_ack_free(cell); @@ -97,7 +99,7 @@ build_linked_ack_cell(uint8_t *cell_out) bool conflux_cell_send_link(const conflux_cell_link_t *link, origin_circuit_t *circ) { - uint8_t payload[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; ssize_t cell_len; tor_assert(link); @@ -131,7 +133,7 @@ conflux_cell_send_link(const conflux_cell_link_t *link, origin_circuit_t *circ) bool conflux_cell_send_linked(const conflux_cell_link_t *link, or_circuit_t *circ) { - uint8_t payload[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; ssize_t cell_len; tor_assert(link); @@ -164,7 +166,7 @@ conflux_cell_send_linked(const conflux_cell_link_t *link, or_circuit_t *circ) bool conflux_cell_send_linked_ack(origin_circuit_t *circ) { - uint8_t payload[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; ssize_t cell_len; tor_assert(circ); @@ -226,16 +228,14 @@ conflux_cell_parse_link_v1(const trn_cell_conflux_link_t *trn_link) } conflux_cell_link_t * -conflux_cell_parse_link(const cell_t *cell, const uint16_t cell_len) +conflux_cell_parse_link(const relay_msg_t *msg) { conflux_cell_link_t *link = NULL; trn_cell_conflux_link_t *trn_cell = NULL; - tor_assert(cell); + tor_assert(msg); - if (trn_cell_conflux_link_parse(&trn_cell, - cell->payload + RELAY_HEADER_SIZE, - cell_len) < 0) { + if (trn_cell_conflux_link_parse(&trn_cell, msg->body, msg->length) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, "Unable to parse CONFLUX_LINK cell."); goto end; @@ -258,10 +258,10 @@ conflux_cell_parse_link(const cell_t *cell, const uint16_t cell_len) } conflux_cell_link_t * -conflux_cell_parse_linked(const cell_t *cell, const uint16_t cell_len) +conflux_cell_parse_linked(const relay_msg_t *msg) { /* At the moment, same exact payload so avoid code duplication. */ - return conflux_cell_parse_link(cell, cell_len); + return conflux_cell_parse_link(msg); } conflux_cell_link_t * @@ -284,15 +284,15 @@ conflux_cell_new_link(const uint8_t *nonce, uint64_t last_seqno_sent, * Extracts the sequence number from a switch cell. */ uint32_t -conflux_cell_parse_switch(const cell_t *cell, uint16_t rh_len) +conflux_cell_parse_switch(const relay_msg_t *msg) { uint32_t seq = 0; trn_cell_conflux_switch_t *switch_cell = NULL; - tor_assert(cell); + + tor_assert(msg); if (trn_cell_conflux_switch_parse(&switch_cell, - cell->payload + RELAY_HEADER_SIZE, - rh_len) < 0) { + msg->body, msg->length) < 0) { log_warn(LD_BUG, "Failed to parse switch cell"); // Zero counts as a failure to the validation, since legs should // not switch after 0 cells. @@ -311,18 +311,18 @@ bool conflux_send_switch_command(circuit_t *send_circ, uint64_t relative_seq) { trn_cell_conflux_switch_t *switch_cell = trn_cell_conflux_switch_new(); - cell_t cell; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; bool ret = true; tor_assert(send_circ); tor_assert(relative_seq < UINT32_MAX); - memset(&cell, 0, sizeof(cell)); - trn_cell_conflux_switch_set_seqnum(switch_cell, (uint32_t)relative_seq); - if (trn_cell_conflux_switch_encode(cell.payload, RELAY_PAYLOAD_SIZE, - switch_cell) < 0) { + ssize_t len = trn_cell_conflux_switch_encode( + payload, RELAY_PAYLOAD_SIZE_MAX, + switch_cell); + if (len < 0) { log_warn(LD_BUG, "Failed to encode conflux switch cell"); ret = false; goto end; @@ -332,18 +332,16 @@ conflux_send_switch_command(circuit_t *send_circ, uint64_t relative_seq) if (CIRCUIT_IS_ORIGIN(send_circ)) { relay_send_command_from_edge(0, send_circ, RELAY_COMMAND_CONFLUX_SWITCH, - (const char*)cell.payload, - RELAY_PAYLOAD_SIZE, + (const char*)payload, len, TO_ORIGIN_CIRCUIT(send_circ)->cpath->prev); } else { relay_send_command_from_edge(0, send_circ, RELAY_COMMAND_CONFLUX_SWITCH, - (const char*)cell.payload, - RELAY_PAYLOAD_SIZE, NULL); + (const char*)payload, len, + NULL); } end: trn_cell_conflux_switch_free(switch_cell); return ret; } - diff --git a/src/core/or/conflux_cell.h b/src/core/or/conflux_cell.h @@ -10,6 +10,7 @@ #define TOR_CONFLUX_CELL_H #include "core/or/or.h" +#include "core/or/relay_msg_st.h" typedef struct conflux_cell_link_t { uint8_t version; @@ -25,12 +26,9 @@ conflux_cell_link_t *conflux_cell_new_link(const uint8_t *nonce, uint64_t last_recv, uint8_t ux); -conflux_cell_link_t *conflux_cell_parse_link(const cell_t *cell, - const uint16_t cell_len); -conflux_cell_link_t *conflux_cell_parse_linked(const cell_t *cell, - const uint16_t cell_le); -uint32_t conflux_cell_parse_switch(const cell_t *cell, - const uint16_t rh_len); +conflux_cell_link_t *conflux_cell_parse_link(const relay_msg_t *msg); +conflux_cell_link_t *conflux_cell_parse_linked(const relay_msg_t *msg); +uint32_t conflux_cell_parse_switch(const relay_msg_t *msg); bool conflux_cell_send_link(const conflux_cell_link_t *link, origin_circuit_t *circ); diff --git a/src/core/or/conflux_pool.c b/src/core/or/conflux_pool.c @@ -196,7 +196,7 @@ conflux_free_(conflux_t *cfx) } SMARTLIST_FOREACH_END(leg); smartlist_free(cfx->legs); - SMARTLIST_FOREACH(cfx->ooo_q, conflux_cell_t *, cell, tor_free(cell)); + SMARTLIST_FOREACH(cfx->ooo_q, conflux_msg_t *, cell, tor_free(cell)); smartlist_free(cfx->ooo_q); memwipe(cfx->nonce, 0, sizeof(cfx->nonce)); @@ -1763,14 +1763,13 @@ conflux_circuit_has_opened(origin_circuit_t *orig_circ) /** Process a CONFLUX_LINK cell which arrived on the given circuit. */ void -conflux_process_link(circuit_t *circ, const cell_t *cell, - const uint16_t cell_len) +conflux_process_link(circuit_t *circ, const relay_msg_t *msg) { unlinked_circuits_t *unlinked = NULL; conflux_cell_link_t *link = NULL; tor_assert(circ); - tor_assert(cell); + tor_assert(msg); if (!conflux_is_enabled(circ)) { circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); @@ -1810,7 +1809,7 @@ conflux_process_link(circuit_t *circ, const cell_t *cell, } /* On errors, logging is emitted in this parsing function. */ - link = conflux_cell_parse_link(cell, cell_len); + link = conflux_cell_parse_link(msg); if (!link) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, "Unable to parse " "CONFLUX_LINK cell. Closing circuit."); @@ -1875,8 +1874,7 @@ conflux_process_link(circuit_t *circ, const cell_t *cell, /** Process a CONFLUX_LINKED cell which arrived on the given circuit. */ void conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint, - const cell_t *cell, - const uint16_t cell_len) + const relay_msg_t *msg) { conflux_cell_link_t *link = NULL; @@ -1936,7 +1934,7 @@ conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint, tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED); /* On errors, logging is emitted in this parsing function. */ - link = conflux_cell_parse_link(cell, cell_len); + link = conflux_cell_parse_link(msg); if (!link) { goto close; } @@ -2008,7 +2006,7 @@ conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint, } /* This cell is now considered valid for clients. */ - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), cell_len); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); goto end; diff --git a/src/core/or/conflux_pool.h b/src/core/or/conflux_pool.h @@ -10,6 +10,7 @@ #define TOR_CONFLUX_POOL_H #include "core/or/or.h" +#include "core/or/relay_msg_st.h" void conflux_pool_init(void); void conflux_notify_shutdown(void); @@ -31,10 +32,9 @@ void conflux_circuit_has_closed(circuit_t *circ); void conflux_circuit_has_opened(origin_circuit_t *orig_circ); void conflux_circuit_about_to_free(circuit_t *circ); -void conflux_process_link(circuit_t *circ, const cell_t *cell, - const uint16_t cell_len); +void conflux_process_link(circuit_t *circ, const relay_msg_t *msg); void conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint, - const cell_t *cell, const uint16_t cell_len); + const relay_msg_t *msg); void conflux_process_linked_ack(circuit_t *circ); typedef struct conflux_t conflux_t; diff --git a/src/core/or/congestion_control_flow.c b/src/core/or/congestion_control_flow.c @@ -71,13 +71,15 @@ double cc_stats_flow_xon_outbuf_ma = 0; void flow_control_new_consensus_params(const networkstatus_t *ns) { + // TODO CGO: These numbers might be wrong for the v1 cell format! + #define CC_XOFF_CLIENT_DFLT 500 #define CC_XOFF_CLIENT_MIN 1 #define CC_XOFF_CLIENT_MAX 10000 xoff_client = networkstatus_get_param(ns, "cc_xoff_client", CC_XOFF_CLIENT_DFLT, CC_XOFF_CLIENT_MIN, - CC_XOFF_CLIENT_MAX)*RELAY_PAYLOAD_SIZE; + CC_XOFF_CLIENT_MAX)*RELAY_PAYLOAD_SIZE_MAX; #define CC_XOFF_EXIT_DFLT 500 #define CC_XOFF_EXIT_MIN 1 @@ -85,7 +87,7 @@ flow_control_new_consensus_params(const networkstatus_t *ns) xoff_exit = networkstatus_get_param(ns, "cc_xoff_exit", CC_XOFF_EXIT_DFLT, CC_XOFF_EXIT_MIN, - CC_XOFF_EXIT_MAX)*RELAY_PAYLOAD_SIZE; + CC_XOFF_EXIT_MAX)*RELAY_PAYLOAD_SIZE_MAX; #define CC_XON_CHANGE_PCT_DFLT 25 #define CC_XON_CHANGE_PCT_MIN 1 @@ -101,7 +103,7 @@ flow_control_new_consensus_params(const networkstatus_t *ns) xon_rate_bytes = networkstatus_get_param(ns, "cc_xon_rate", CC_XON_RATE_BYTES_DFLT, CC_XON_RATE_BYTES_MIN, - CC_XON_RATE_BYTES_MAX)*RELAY_PAYLOAD_SIZE; + CC_XON_RATE_BYTES_MAX)*RELAY_PAYLOAD_SIZE_MAX; #define CC_XON_EWMA_CNT_DFLT (2) #define CC_XON_EWMA_CNT_MIN (2) @@ -232,10 +234,8 @@ circuit_send_stream_xon(edge_connection_t *stream) */ bool circuit_process_stream_xoff(edge_connection_t *conn, - const crypt_path_t *layer_hint, - const cell_t *cell) + const crypt_path_t *layer_hint) { - (void)cell; bool retval = true; if (BUG(!conn)) { @@ -327,7 +327,7 @@ circuit_process_stream_xoff(edge_connection_t *conn, bool circuit_process_stream_xon(edge_connection_t *conn, const crypt_path_t *layer_hint, - const cell_t *cell) + const relay_msg_t *msg) { xon_cell_t *xon; bool retval = true; @@ -351,8 +351,7 @@ circuit_process_stream_xon(edge_connection_t *conn, return false; } - if (xon_cell_parse(&xon, cell->payload+RELAY_HEADER_SIZE, - CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) { + if (xon_cell_parse(&xon, msg->body, msg->length) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_EDGE, "Received malformed XON cell."); return false; @@ -480,7 +479,8 @@ flow_control_decide_xoff(edge_connection_t *stream) * do this because writes only happen when the socket unblocks, so * may not otherwise notice accumulation of data in the outbuf for * advisory XONs. */ - if (total_buffered > MAX_EXPECTED_CELL_BURST*RELAY_PAYLOAD_SIZE) { + // TODO CGO: This might be wrong for the v1 cell format! + if (total_buffered > MAX_EXPECTED_CELL_BURST*RELAY_PAYLOAD_SIZE_MAX) { flow_control_decide_xon(stream, 0); } @@ -713,4 +713,3 @@ conn_uses_flow_control(connection_t *conn) return ret; } - diff --git a/src/core/or/congestion_control_flow.h b/src/core/or/congestion_control_flow.h @@ -13,14 +13,15 @@ #include "core/or/circuit_st.h" #include "core/or/edge_connection_st.h" +struct relay_msg_t; + void flow_control_new_consensus_params(const struct networkstatus_t *); bool circuit_process_stream_xoff(edge_connection_t *conn, - const crypt_path_t *layer_hint, - const cell_t *cell); + const crypt_path_t *layer_hint); bool circuit_process_stream_xon(edge_connection_t *conn, const crypt_path_t *layer_hint, - const cell_t *cell); + const struct relay_msg_t *msg); int flow_control_decide_xoff(edge_connection_t *stream); void flow_control_decide_xon(edge_connection_t *stream, size_t n_written); diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c @@ -513,7 +513,7 @@ clip_dns_fuzzy_ttl(uint32_t ttl) int connection_edge_end(edge_connection_t *conn, uint8_t reason) { - char payload[RELAY_PAYLOAD_SIZE]; + char payload[RELAY_PAYLOAD_SIZE_MAX]; size_t payload_len=1; circuit_t *circ; uint8_t control_reason = reason; @@ -3238,8 +3238,8 @@ connection_ap_get_begincell_flags(entry_connection_t *ap_conn) MOCK_IMPL(int, connection_ap_handshake_send_begin,(entry_connection_t *ap_conn)) { - char payload[CELL_PAYLOAD_SIZE]; - int payload_len; + char payload[RELAY_PAYLOAD_SIZE_MAX]; + size_t payload_len; int begin_type; const or_options_t *options = get_options(); origin_circuit_t *circ; @@ -3264,17 +3264,20 @@ connection_ap_handshake_send_begin,(entry_connection_t *ap_conn)) return -1; } + size_t payload_max = circuit_max_relay_payload( + edge_conn->on_circuit, edge_conn->cpath_layer, + RELAY_COMMAND_BEGIN); /* Set up begin cell flags. */ edge_conn->begincell_flags = connection_ap_get_begincell_flags(ap_conn); - tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d", + tor_snprintf(payload,payload_max, "%s:%d", (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL || circ->base_.purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED || circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) ? ap_conn->socks_request->address : "", ap_conn->socks_request->port); - payload_len = (int)strlen(payload)+1; - if (payload_len <= RELAY_PAYLOAD_SIZE - 4 && edge_conn->begincell_flags) { + payload_len = strlen(payload)+1; + if (payload_len <= payload_max - 4 && edge_conn->begincell_flags) { set_uint32(payload + payload_len, htonl(edge_conn->begincell_flags)); payload_len += 4; } @@ -3816,33 +3819,27 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply, * we don't. **/ STATIC int -begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, +begin_cell_parse(const relay_msg_t *msg, begin_cell_t *bcell, uint8_t *end_reason_out) { - relay_header_t rh; const uint8_t *body, *nul; memset(bcell, 0, sizeof(*bcell)); *end_reason_out = END_STREAM_REASON_MISC; - relay_header_unpack(&rh, cell->payload); - if (rh.length > RELAY_PAYLOAD_SIZE) { - return -2; /*XXXX why not TORPROTOCOL? */ - } - - bcell->stream_id = rh.stream_id; + bcell->stream_id = msg->stream_id; - if (rh.command == RELAY_COMMAND_BEGIN_DIR) { + if (msg->command == RELAY_COMMAND_BEGIN_DIR) { bcell->is_begindir = 1; return 0; - } else if (rh.command != RELAY_COMMAND_BEGIN) { - log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command); + } else if (msg->command != RELAY_COMMAND_BEGIN) { + log_warn(LD_BUG, "Got an unexpected command %u", msg->command); *end_reason_out = END_STREAM_REASON_INTERNAL; return -1; } - body = cell->payload + RELAY_HEADER_SIZE; - nul = memchr(body, 0, rh.length); + body = msg->body; + nul = memchr(body, 0, msg->length); if (! nul) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay begin cell has no \\0. Closing."); @@ -3865,7 +3862,7 @@ begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, *end_reason_out = END_STREAM_REASON_TORPROTOCOL; return -1; } - if (body + rh.length >= nul + 4) + if (body + msg->length >= nul + 4) bcell->flags = ntohl(get_uint32(nul+1)); return 0; @@ -3978,10 +3975,9 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn) * Else return 0. */ int -connection_exit_begin_conn(cell_t *cell, circuit_t *circ) +connection_exit_begin_conn(const relay_msg_t *msg, circuit_t *circ) { edge_connection_t *n_stream; - relay_header_t rh; char *address = NULL; uint16_t port = 0; or_circuit_t *or_circ = NULL; @@ -4002,25 +3998,22 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) layer_hint = origin_circ->cpath->prev; } - relay_header_unpack(&rh, cell->payload); - if (rh.length > RELAY_PAYLOAD_SIZE) - return -END_CIRC_REASON_TORPROTOCOL; - if (!server_mode(options) && circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay begin cell at non-server. Closing."); - relay_send_end_cell_from_edge(rh.stream_id, circ, + relay_send_end_cell_from_edge(msg->stream_id, circ, END_STREAM_REASON_EXITPOLICY, NULL); return 0; } - rv = begin_cell_parse(cell, &bcell, &end_reason); + rv = begin_cell_parse(msg, &bcell, &end_reason); if (rv < -1) { return -END_CIRC_REASON_TORPROTOCOL; } else if (rv == -1) { tor_free(bcell.address); - relay_send_end_cell_from_edge(rh.stream_id, circ, end_reason, layer_hint); + relay_send_end_cell_from_edge(msg->stream_id, circ, end_reason, + layer_hint); return 0; } @@ -4044,7 +4037,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) safe_str(channel_describe_peer(or_circ->p_chan)), client_chan ? "on first hop of circuit" : "from unknown relay"); - relay_send_end_cell_from_edge(rh.stream_id, circ, + relay_send_end_cell_from_edge(msg->stream_id, circ, client_chan ? END_STREAM_REASON_TORPROTOCOL : END_STREAM_REASON_MISC, @@ -4053,11 +4046,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) return 0; } } - } else if (rh.command == RELAY_COMMAND_BEGIN_DIR) { + } else if (msg->command == RELAY_COMMAND_BEGIN_DIR) { if (!directory_permits_begindir_requests(options) || circ->purpose != CIRCUIT_PURPOSE_OR) { - relay_send_end_cell_from_edge(rh.stream_id, circ, - END_STREAM_REASON_NOTDIRECTORY, layer_hint); + relay_send_end_cell_from_edge(msg->stream_id, circ, + END_STREAM_REASON_NOTDIRECTORY, + layer_hint); return 0; } /* Make sure to get the 'real' address of the previous hop: the @@ -4075,8 +4069,8 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * isn't "really" a connection here. But we * need to set it to something nonzero. */ } else { - log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command); - relay_send_end_cell_from_edge(rh.stream_id, circ, + log_warn(LD_BUG, "Got an unexpected command %u", msg->command); + relay_send_end_cell_from_edge(msg->stream_id, circ, END_STREAM_REASON_INTERNAL, layer_hint); return 0; } @@ -4087,7 +4081,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) /* If you don't want IPv4, I can't help. */ if (bcell.flags & BEGIN_FLAG_IPV4_NOT_OK) { tor_free(address); - relay_send_end_cell_from_edge(rh.stream_id, circ, + relay_send_end_cell_from_edge(msg->stream_id, circ, END_STREAM_REASON_EXITPOLICY, layer_hint); return 0; } @@ -4104,7 +4098,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) n_stream->base_.purpose = EXIT_PURPOSE_CONNECT; n_stream->begincell_flags = bcell.flags; - n_stream->stream_id = rh.stream_id; + n_stream->stream_id = msg->stream_id; n_stream->base_.port = port; /* leave n_stream->s at -1, because it's not yet valid */ n_stream->package_window = STREAMWINDOW_START; @@ -4119,7 +4113,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) if (ret == 0) { /* This was a valid cell. Count it as delivered + overhead. */ - circuit_read_valid_data(origin_circ, rh.length); + circuit_read_valid_data(origin_circ, msg->length); } return ret; } @@ -4130,7 +4124,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) /* If we're hibernating or shutting down, we refuse to open new streams. */ if (we_are_hibernating()) { - relay_send_end_cell_from_edge(rh.stream_id, circ, + relay_send_end_cell_from_edge(msg->stream_id, circ, END_STREAM_REASON_HIBERNATING, NULL); connection_free_(TO_CONN(n_stream)); return 0; @@ -4138,7 +4132,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) n_stream->on_circuit = circ; - if (rh.command == RELAY_COMMAND_BEGIN_DIR) { + if (msg->command == RELAY_COMMAND_BEGIN_DIR) { tor_addr_t tmp_addr; tor_assert(or_circ); if (or_circ->p_chan && @@ -4159,8 +4153,8 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) case DOS_STREAM_DEFENSE_REFUSE_STREAM: // we don't use END_STREAM_REASON_RESOURCELIMIT because it would make a // client mark us as non-functional until they get a new consensus. - relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_MISC, - layer_hint); + relay_send_end_cell_from_edge(msg->stream_id, circ, + END_STREAM_REASON_MISC, layer_hint); connection_free_(TO_CONN(n_stream)); return 0; case DOS_STREAM_DEFENSE_CLOSE_CIRCUIT: @@ -4176,7 +4170,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) connection_exit_connect(n_stream); return 0; case -1: /* resolve failed */ - relay_send_end_cell_from_edge(rh.stream_id, circ, + relay_send_end_cell_from_edge(msg->stream_id, circ, END_STREAM_REASON_RESOLVEFAILED, NULL); /* n_stream got freed. don't touch it. */ break; @@ -4196,16 +4190,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * Else return 0. */ int -connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) +connection_exit_begin_resolve(const relay_msg_t *msg, or_circuit_t *circ) { edge_connection_t *dummy_conn; - relay_header_t rh; dos_stream_defense_type_t dos_defense_type; assert_circuit_ok(TO_CIRCUIT(circ)); - relay_header_unpack(&rh, cell->payload); - if (rh.length > RELAY_PAYLOAD_SIZE) - return 0; /* Note the RESOLVE stream as seen. */ rep_hist_note_exit_stream(RELAY_COMMAND_RESOLVE); @@ -4218,10 +4208,8 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) * the housekeeping in dns.c would get way more complicated.) */ dummy_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET); - dummy_conn->stream_id = rh.stream_id; - dummy_conn->base_.address = tor_strndup( - (char*)cell->payload+RELAY_HEADER_SIZE, - rh.length); + dummy_conn->stream_id = msg->stream_id; + dummy_conn->base_.address = tor_strndup((char *) msg->body, msg->length); dummy_conn->base_.port = 0; dummy_conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; dummy_conn->base_.purpose = EXIT_PURPOSE_RESOLVE; diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h @@ -12,6 +12,8 @@ #ifndef TOR_CONNECTION_EDGE_H #define TOR_CONNECTION_EDGE_H +#include "core/or/relay_msg_st.h" + #include "lib/testsupport/testsupport.h" #include "lib/encoding/confline.h" @@ -129,8 +131,8 @@ void connection_ap_handshake_socks_resolved_addr(entry_connection_t *conn, int ttl, time_t expires); -int connection_exit_begin_conn(cell_t *cell, circuit_t *circ); -int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ); +int connection_exit_begin_conn(const relay_msg_t *msg, circuit_t *circ); +int connection_exit_begin_resolve(const relay_msg_t *msg, or_circuit_t *circ); void connection_exit_connect(edge_connection_t *conn); int connection_edge_is_rendezvous_stream(const edge_connection_t *conn); int connection_ap_can_use_exit(const entry_connection_t *conn, @@ -268,8 +270,8 @@ typedef struct begin_cell_t { unsigned is_begindir : 1; } begin_cell_t; -STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, - uint8_t *end_reason_out); +STATIC int begin_cell_parse(const relay_msg_t *msg, begin_cell_t *bcell, + uint8_t *end_reason_out); STATIC int connected_cell_format_payload(uint8_t *payload_out, const tor_addr_t *addr, uint32_t ttl); diff --git a/src/core/or/crypt_path.c b/src/core/or/crypt_path.c @@ -71,6 +71,9 @@ cpath_append_hop(crypt_path_t **head_ptr, extend_info_t *choice) hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; + // TODO CGO: Initialize this from a real decision. + hop->relay_cell_format = RELAY_CELL_FORMAT_V0; + return 0; } @@ -198,7 +201,7 @@ cpath_get_incoming_digest(const crypt_path_t *cpath) void cpath_set_cell_forward_digest(crypt_path_t *cpath, cell_t *cell) { - relay_set_digest(cpath->pvt_crypto.f_digest, cell); + relay_set_digest_v0(cpath->pvt_crypto.f_digest, cell); } /************ cpath sendme API ***************************/ diff --git a/src/core/or/crypt_path_st.h b/src/core/or/crypt_path_st.h @@ -87,6 +87,9 @@ struct crypt_path_t { /** Congestion control info */ struct congestion_control_t *ccontrol; + /** Format to use when exchanging relay cells with this relay. */ + relay_cell_fmt_t relay_cell_format; + /*********************** Private members ****************************/ /** Private member: Cryptographic state used for encrypting and diff --git a/src/core/or/include.am b/src/core/or/include.am @@ -30,6 +30,7 @@ LIBTOR_APP_A_SOURCES += \ src/core/or/protover.c \ src/core/or/reasons.c \ src/core/or/relay.c \ + src/core/or/relay_msg.c \ src/core/or/scheduler.c \ src/core/or/scheduler_kist.c \ src/core/or/scheduler_vanilla.c \ @@ -105,6 +106,8 @@ noinst_HEADERS += \ src/core/or/reasons.h \ src/core/or/relay.h \ src/core/or/relay_crypto_st.h \ + src/core/or/relay_msg.h \ + src/core/or/relay_msg_st.h \ src/core/or/scheduler.h \ src/core/or/sendme.h \ src/core/or/congestion_control_flow.h \ diff --git a/src/core/or/onion.c b/src/core/or/onion.c @@ -128,7 +128,7 @@ parse_create2_payload(create_cell_t *cell_out, const uint8_t *p, size_t p_len) handshake_type = ntohs(get_uint16(p)); handshake_len = ntohs(get_uint16(p+2)); - if (handshake_len > CELL_PAYLOAD_SIZE - 4 || handshake_len > p_len - 4) + if (handshake_len > MAX_CREATE_LEN || handshake_len > p_len - 4) return -1; if (handshake_type == ONION_HANDSHAKE_TYPE_FAST) return -1; @@ -183,7 +183,7 @@ check_created_cell(const created_cell_t *cell) return -1; break; case CELL_CREATED2: - if (cell->handshake_len > RELAY_PAYLOAD_SIZE-2) + if (cell->handshake_len > MAX_CREATED_LEN) return -1; break; } @@ -211,7 +211,7 @@ created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in) const uint8_t *p = cell_in->payload; cell_out->cell_type = CELL_CREATED2; cell_out->handshake_len = ntohs(get_uint16(p)); - if (cell_out->handshake_len > CELL_PAYLOAD_SIZE - 2) + if (cell_out->handshake_len > MAX_CREATED_LEN) return -1; memcpy(cell_out->reply, p+2, cell_out->handshake_len); break; @@ -353,7 +353,7 @@ extend_cell_parse,(extend_cell_t *cell_out, tor_assert(cell_out); tor_assert(payload); - if (payload_length > RELAY_PAYLOAD_SIZE) + if (payload_length > RELAY_PAYLOAD_SIZE_MAX) return -1; switch (command) { @@ -412,7 +412,7 @@ extended_cell_parse(extended_cell_t *cell_out, tor_assert(payload); memset(cell_out, 0, sizeof(*cell_out)); - if (payload_len > RELAY_PAYLOAD_SIZE) + if (payload_len > RELAY_PAYLOAD_SIZE_MAX) return -1; switch (command) { @@ -423,7 +423,7 @@ extended_cell_parse(extended_cell_t *cell_out, cell_out->cell_type = RELAY_COMMAND_EXTENDED2; cell_out->created_cell.cell_type = CELL_CREATED2; cell_out->created_cell.handshake_len = ntohs(get_uint16(payload)); - if (cell_out->created_cell.handshake_len > RELAY_PAYLOAD_SIZE - 2 || + if (cell_out->created_cell.handshake_len > RELAY_PAYLOAD_SIZE_MAX - 2 || cell_out->created_cell.handshake_len > payload_len - 2) return -1; memcpy(cell_out->created_cell.reply, payload+2, @@ -544,7 +544,9 @@ should_include_ed25519_id_extend_cells(const networkstatus_t *ns, /** Format the EXTEND{,2} cell in <b>cell_in</b>, storing its relay payload in * <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the * relay command in *<b>command_out</b>. The <b>payload_out</b> must have - * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ + * RELAY_PAYLOAD_SIZE_MAX bytes available. + * + * Return 0 on success, -1 on failure. */ int extend_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extend_cell_t *cell_in) @@ -555,7 +557,7 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out, p = payload_out; - memset(p, 0, RELAY_PAYLOAD_SIZE); + memset(p, 0, RELAY_PAYLOAD_SIZE_MAX); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTEND: @@ -618,7 +620,7 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out, cell_in->create_cell.handshake_len); ssize_t len_encoded = extend2_cell_body_encode( - payload_out, RELAY_PAYLOAD_SIZE, + payload_out, RELAY_PAYLOAD_SIZE_MAX, cell); extend2_cell_body_free(cell); if (len_encoded < 0 || len_encoded > UINT16_MAX) @@ -636,7 +638,9 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out, /** Format the EXTENDED{,2} cell in <b>cell_in</b>, storing its relay payload * in <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the * relay command in *<b>command_out</b>. The <b>payload_out</b> must have - * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ + * RELAY_PAYLOAD_SIZE_MAX bytes available. + * + * Return 0 on success, -1 on failure. */ int extended_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extended_cell_t *cell_in) @@ -646,7 +650,7 @@ extended_cell_format(uint8_t *command_out, uint16_t *len_out, return -1; p = payload_out; - memset(p, 0, RELAY_PAYLOAD_SIZE); + memset(p, 0, RELAY_PAYLOAD_SIZE_MAX); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTENDED: @@ -656,7 +660,7 @@ extended_cell_format(uint8_t *command_out, uint16_t *len_out, *command_out = RELAY_COMMAND_EXTENDED2; *len_out = 2 + cell_in->created_cell.handshake_len; set_uint16(payload_out, htons(cell_in->created_cell.handshake_len)); - if (2+cell_in->created_cell.handshake_len > RELAY_PAYLOAD_SIZE) + if (cell_in->created_cell.handshake_len > MAX_CREATED_LEN) return -1; memcpy(payload_out+2, cell_in->created_cell.reply, cell_in->created_cell.handshake_len); diff --git a/src/core/or/onion.h b/src/core/or/onion.h @@ -20,6 +20,9 @@ struct curve25519_public_key_t; #define MAX_ONIONSKIN_CHALLENGE_LEN 255 #define MAX_ONIONSKIN_REPLY_LEN 255 +#define MAX_CREATE_LEN (CELL_PAYLOAD_SIZE - 4) +#define MAX_CREATED_LEN (CELL_PAYLOAD_SIZE - 2) + /** A parsed CREATE, CREATE_FAST, or CREATE2 cell. */ typedef struct create_cell_t { /** The cell command. One of CREATE{,_FAST,2} */ @@ -29,7 +32,7 @@ typedef struct create_cell_t { /** The number of bytes used in <b>onionskin</b>. */ uint16_t handshake_len; /** The client-side message for the circuit creation handshake. */ - uint8_t onionskin[CELL_PAYLOAD_SIZE - 4]; + uint8_t onionskin[MAX_CREATE_LEN]; } create_cell_t; /** A parsed CREATED, CREATED_FAST, or CREATED2 cell. */ @@ -39,7 +42,7 @@ typedef struct created_cell_t { /** The number of bytes used in <b>reply</b>. */ uint16_t handshake_len; /** The server-side message for the circuit creation handshake. */ - uint8_t reply[CELL_PAYLOAD_SIZE - 2]; + uint8_t reply[MAX_CREATED_LEN]; } created_cell_t; /** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */ diff --git a/src/core/or/or.h b/src/core/or/or.h @@ -222,6 +222,52 @@ struct curve25519_public_key_t; #define RELAY_COMMAND_XOFF 43 #define RELAY_COMMAND_XON 44 +/* NOTE: Any new command from above MUST be added to this function. */ +/** Helper to learn if we know the relay command. Unfortuantely, they are not + * contigous and so we need this kind of big switch. We could do better but for + * now, we'll run with this. */ +static inline bool +is_known_relay_command(const uint8_t cmd) +{ + switch (cmd) { + case RELAY_COMMAND_BEGIN: + case RELAY_COMMAND_BEGIN_DIR: + case RELAY_COMMAND_CONFLUX_LINK: + case RELAY_COMMAND_CONFLUX_LINKED: + case RELAY_COMMAND_CONFLUX_LINKED_ACK: + case RELAY_COMMAND_CONFLUX_SWITCH: + case RELAY_COMMAND_CONNECTED: + case RELAY_COMMAND_DATA: + case RELAY_COMMAND_DROP: + case RELAY_COMMAND_END: + case RELAY_COMMAND_ESTABLISH_INTRO: + case RELAY_COMMAND_ESTABLISH_RENDEZVOUS: + case RELAY_COMMAND_EXTEND2: + case RELAY_COMMAND_EXTEND: + case RELAY_COMMAND_EXTENDED2: + case RELAY_COMMAND_EXTENDED: + case RELAY_COMMAND_INTRODUCE1: + case RELAY_COMMAND_INTRODUCE2: + case RELAY_COMMAND_INTRODUCE_ACK: + case RELAY_COMMAND_INTRO_ESTABLISHED: + case RELAY_COMMAND_PADDING_NEGOTIATE: + case RELAY_COMMAND_PADDING_NEGOTIATED: + case RELAY_COMMAND_RENDEZVOUS1: + case RELAY_COMMAND_RENDEZVOUS2: + case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: + case RELAY_COMMAND_RESOLVE: + case RELAY_COMMAND_RESOLVED: + case RELAY_COMMAND_SENDME: + case RELAY_COMMAND_TRUNCATE: + case RELAY_COMMAND_TRUNCATED: + case RELAY_COMMAND_XOFF: + case RELAY_COMMAND_XON: + return true; + default: + return false; + } +} + /* Reasons why an OR connection is closed. */ #define END_OR_CONN_REASON_DONE 1 #define END_OR_CONN_REASON_REFUSED 2 /* connection refused */ @@ -454,13 +500,20 @@ typedef enum { #define SOCKS4_NETWORK_LEN 8 /* - * Relay payload: + * Relay cell body (V0): * Relay command [1 byte] * Recognized [2 bytes] * Stream ID [2 bytes] * Partial SHA-1 [4 bytes] * Length [2 bytes] * Relay payload [498 bytes] + * + * Relay cell body (V1): + * Tag [16 bytes] + * Command [1 byte] + * Length [2 bytes] + * Stream ID [2 bytes, Optional, depends on command] + * Relay payload [488 bytes _or_ 490 bytes] */ /** Number of bytes in a cell, minus cell header. */ @@ -472,6 +525,14 @@ typedef enum { /** Maximum length of a header on a variable-length cell. */ #define VAR_CELL_MAX_HEADER_SIZE 7 +/** Which format should we use for relay cells? */ +typedef enum relay_cell_fmt_t { + /** Our original format, with 2 byte recognized field and a 4-byte digest */ + RELAY_CELL_FORMAT_V0, + /** New format introduced for CGO, with 16 byte tag. */ + RELAY_CELL_FORMAT_V1, +} relay_cell_fmt_t; + static int get_cell_network_size(int wide_circ_ids); static inline int get_cell_network_size(int wide_circ_ids) { @@ -489,11 +550,30 @@ static inline int get_circ_id_size(int wide_circ_ids) return wide_circ_ids ? 4 : 2; } -/** Number of bytes in a relay cell's header (not including general cell - * header). */ -#define RELAY_HEADER_SIZE (1+2+2+4+2) -/** Largest number of bytes that can fit in a relay cell payload. */ -#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) +/** Number of bytes used for a relay cell's header, in the v0 format. */ +#define RELAY_HEADER_SIZE_V0 (1+2+2+4+2) +/** Number of bytes used for a relay cell's header, in the v1 format, + * if no StreamID is used. */ +#define RELAY_HEADER_SIZE_V1_NO_STREAM_ID (16+1+2) +/** Number of bytes used for a relay cell's header, in the v1 format, + * if a StreamID is used. */ +#define RELAY_HEADER_SIZE_V1_WITH_STREAM_ID (16+1+2+2) + +/** Largest number of bytes that can fit in any relay cell payload. + * + * Note that the actual maximum may be smaller if the V1 cell format + * is in use; see relay_cell_max_payload_size() for the real maximum. + */ +#define RELAY_PAYLOAD_SIZE_MAX (CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0) + +/** Smallest capacity of any relay cell payload. */ +#define RELAY_PAYLOAD_SIZE_MIN \ + (CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID) + +#ifdef TOR_UNIT_TESTS +// This name is for testing only. +#define RELAY_PAYLOAD_SIZE RELAY_PAYLOAD_SIZE_MAX +#endif /** Identifies a circuit on an or_connection */ typedef uint32_t circid_t; @@ -524,6 +604,11 @@ typedef struct destroy_cell_t destroy_cell_t; typedef struct destroy_cell_queue_t destroy_cell_queue_t; typedef struct ext_or_cmd_t ext_or_cmd_t; +#ifdef TOR_UNIT_TESTS +/* This is a vestigial type used only for testing. + * All current code should instead use relay_msg_t and related accessors. + */ + /** Beginning of a RELAY cell payload. */ typedef struct { uint8_t command; /**< The end-to-end relay command. */ @@ -532,6 +617,7 @@ typedef struct { char integrity[4]; /**< Used to tell whether cell is corrupted. */ uint16_t length; /**< How long is the payload body? */ } relay_header_t; +#endif typedef struct socks_request_t socks_request_t; typedef struct entry_port_cfg_t entry_port_cfg_t; diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h @@ -106,6 +106,10 @@ struct or_circuit_t { /** RELAY_BEGIN and RELAY_RESOLVE cell bucket controlling how much can go on * this circuit. Only used if this is the end of a circuit on an exit node.*/ token_bucket_ctr_t stream_limiter; + + /** Format to use when exchanging relay cells with the client + * who built this circuit. */ + relay_cell_fmt_t relay_cell_format; }; #endif /* !defined(OR_CIRCUIT_ST_H) */ diff --git a/src/core/or/relay.c b/src/core/or/relay.c @@ -45,6 +45,7 @@ * types of relay cells, launching requests or transmitting data as needed. **/ +#include "lib/log/log.h" #define RELAY_PRIVATE #include "core/or/or.h" #include "feature/client/addressmap.h" @@ -84,6 +85,7 @@ #include "core/or/scheduler.h" #include "feature/hs/hs_metrics.h" #include "feature/stats/rephist.h" +#include "core/or/relay_msg.h" #include "core/or/cell_st.h" #include "core/or/cell_queue_st.h" @@ -102,8 +104,10 @@ #include "core/or/conflux.h" #include "core/or/conflux_util.h" #include "core/or/conflux_pool.h" +#include "core/or/relay_msg_st.h" -static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, +static edge_connection_t *relay_lookup_conn(circuit_t *circ, + const relay_msg_t *msg, cell_direction_t cell_direction, crypt_path_t *layer_hint); @@ -119,11 +123,10 @@ static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ, entry_connection_t *conn, node_t *node, const tor_addr_t *addr); -static int connection_edge_process_ordered_relay_cell(cell_t *cell, +static int connection_edge_process_ordered_relay_cell(const relay_msg_t *msg, circuit_t *circ, edge_connection_t *conn, - crypt_path_t *layer_hint, - relay_header_t *rh); + crypt_path_t *layer_hint); static void set_block_state_for_streams(circuit_t *circ, edge_connection_t *stream_list, int block, streamid_t stream_id); @@ -256,14 +259,23 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, if (recognized) { edge_connection_t *conn = NULL; + relay_cell_fmt_t format = circuit_get_relay_format(circ, layer_hint); /* Recognized cell, the cell digest has been updated, we'll record it for * the SENDME if need be. */ sendme_record_received_cell_digest(circ, layer_hint); + relay_msg_t msg_buf; + if (relay_msg_decode_cell_in_place(format, cell, &msg_buf) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received undecodable relay cell"); + return -END_CIRC_REASON_TORPROTOCOL; + } + const relay_msg_t *msg = &msg_buf; + if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { - if (pathbias_check_probe_response(circ, cell) == -1) { - pathbias_count_valid_cells(circ, cell); + if (pathbias_check_probe_response(circ, msg) == -1) { + pathbias_count_valid_cells(circ, msg); } /* We need to drop this cell no matter what to avoid code that expects @@ -271,11 +283,11 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, return 0; } - conn = relay_lookup_conn(circ, cell, cell_direction, layer_hint); + conn = relay_lookup_conn(circ, msg, cell_direction, layer_hint); if (cell_direction == CELL_DIRECTION_OUT) { ++stats_n_relay_cells_delivered; log_debug(LD_OR,"Sending away from origin."); - reason = connection_edge_process_relay_cell(cell, circ, conn, NULL); + reason = connection_edge_process_relay_cell(msg, circ, conn, NULL); if (reason < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "connection_edge_process_relay_cell (away from origin) " @@ -286,7 +298,7 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, if (cell_direction == CELL_DIRECTION_IN) { ++stats_n_relay_cells_delivered; log_debug(LD_OR,"Sending to origin."); - reason = connection_edge_process_relay_cell(cell, circ, conn, + reason = connection_edge_process_relay_cell(msg, circ, conn, layer_hint); if (reason < 0) { /* If a client is trying to connect to unknown hidden service port, @@ -443,15 +455,12 @@ circuit_package_relay_cell, (cell_t *cell, circuit_t *circ, * attached to circ, return that conn, else return NULL. */ static edge_connection_t * -relay_lookup_conn(circuit_t *circ, cell_t *cell, +relay_lookup_conn(circuit_t *circ, const relay_msg_t *msg, cell_direction_t cell_direction, crypt_path_t *layer_hint) { edge_connection_t *tmpconn; - relay_header_t rh; - relay_header_unpack(&rh, cell->payload); - - if (!rh.stream_id) + if (!msg->stream_id) return NULL; /* IN or OUT cells could have come from either direction, now @@ -460,19 +469,19 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, if (CIRCUIT_IS_ORIGIN(circ)) { for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && + if (msg->stream_id == tmpconn->stream_id && !tmpconn->base_.marked_for_close && edge_uses_cpath(tmpconn, layer_hint)) { - log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); + log_debug(LD_APP,"found conn for stream %d.", msg->stream_id); return tmpconn; } } } else { for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && + if (msg->stream_id == tmpconn->stream_id && !tmpconn->base_.marked_for_close) { - log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); + log_debug(LD_EXIT,"found conn for stream %d.", msg->stream_id); if (cell_direction == CELL_DIRECTION_OUT || connection_edge_is_rendezvous_stream(tmpconn)) return tmpconn; @@ -480,9 +489,9 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, } for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream) { - if (rh.stream_id == tmpconn->stream_id && + if (msg->stream_id == tmpconn->stream_id && !tmpconn->base_.marked_for_close) { - log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); + log_debug(LD_EXIT,"found conn for stream %d.", msg->stream_id); return tmpconn; } } @@ -490,6 +499,7 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, return NULL; /* probably a begin relay cell */ } +#ifdef TOR_UNIT_TESTS /** Pack the relay_header_t host-order structure <b>src</b> into * network-order in the buffer <b>dest</b>. See tor-spec.txt for details * about the wire format. @@ -516,6 +526,7 @@ relay_header_unpack(relay_header_t *dest, const uint8_t *src) memcpy(dest->integrity, src+5, 4); dest->length = ntohs(get_uint16(src+9)); } +#endif /** Convert the relay <b>command</b> into a human-readable string. */ const char * @@ -561,64 +572,6 @@ relay_command_to_string(uint8_t command) } } -/** When padding a cell with randomness, leave this many zeros after the - * payload. */ -#define CELL_PADDING_GAP 4 - -/** Return the offset where the padding should start. The <b>data_len</b> is - * the relay payload length expected to be put in the cell. It can not be - * bigger than RELAY_PAYLOAD_SIZE else this function assert(). - * - * Value will always be smaller than CELL_PAYLOAD_SIZE because this offset is - * for the entire cell length not just the data payload length. Zero is - * returned if there is no room for padding. - * - * This function always skips the first 4 bytes after the payload because - * having some unused zero bytes has saved us a lot of times in the past. */ - -STATIC size_t -get_pad_cell_offset(size_t data_len) -{ - /* This is never supposed to happen but in case it does, stop right away - * because if tor is tricked somehow into not adding random bytes to the - * payload with this function returning 0 for a bad data_len, the entire - * authenticated SENDME design can be bypassed leading to bad denial of - * service attacks. */ - tor_assert(data_len <= RELAY_PAYLOAD_SIZE); - - /* If the offset is larger than the cell payload size, we return an offset - * of zero indicating that no padding needs to be added. */ - size_t offset = RELAY_HEADER_SIZE + data_len + CELL_PADDING_GAP; - if (offset >= CELL_PAYLOAD_SIZE) { - return 0; - } - return offset; -} - -/* Add random bytes to the unused portion of the payload, to foil attacks - * where the other side can predict all of the bytes in the payload and thus - * compute the authenticated SENDME cells without seeing the traffic. See - * proposal 289. */ -static void -pad_cell_payload(uint8_t *cell_payload, size_t data_len) -{ - size_t pad_offset, pad_len; - - tor_assert(cell_payload); - - pad_offset = get_pad_cell_offset(data_len); - if (pad_offset == 0) { - /* We can't add padding so we are done. */ - return; - } - - /* Remember here that the cell_payload is the length of the header and - * payload size so we offset it using the full length of the cell. */ - pad_len = CELL_PAYLOAD_SIZE - pad_offset; - crypto_fast_rng_getbytes(get_thread_fast_rng(), - cell_payload + pad_offset, pad_len); -} - /** Make a relay cell out of <b>relay_command</b> and <b>payload</b>, and send * it onto the open circuit <b>circ</b>. <b>stream_id</b> is the ID on * <b>circ</b> for the stream that's sending the relay cell, or 0 if it's a @@ -635,7 +588,6 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *orig_circ, const char *filename, int lineno)) { cell_t cell; - relay_header_t rh; cell_direction_t cell_direction; circuit_t *circ = orig_circ; @@ -660,9 +612,35 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *orig_circ, /* XXXX NM Split this function into a separate versions per circuit type? */ tor_assert(circ); - tor_assert(payload_len <= RELAY_PAYLOAD_SIZE); - memset(&cell, 0, sizeof(cell_t)); + size_t msg_body_len; + { + relay_cell_fmt_t cell_format = circuit_get_relay_format(circ, cpath_layer); + relay_msg_t msg; + if (payload_len > + relay_cell_max_payload_size(cell_format, relay_command)) { + // TODO CGO: Rate-limit this? + log_warn(LD_BUG, "Tried to send a command %d of length %d in " + "a v%d cell, from %s:%d", + (int)relay_command, (int)payload_len, (int)cell_format, + filename, lineno); + circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + return -1; + } + + msg.command = relay_command; + msg.stream_id = stream_id; + msg.length = payload_len; + msg.body = (const uint8_t *) payload; + msg_body_len = msg.length; + + if (relay_msg_encode_cell(cell_format, &msg, &cell) < 0) { + // We already called IF_BUG_ONCE in relay_msg_encode_cell. + circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + return -1; + } + } + cell.command = CELL_RELAY; if (CIRCUIT_IS_ORIGIN(circ)) { tor_assert(cpath_layer); @@ -674,18 +652,6 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *orig_circ, cell_direction = CELL_DIRECTION_IN; } - memset(&rh, 0, sizeof(rh)); - rh.command = relay_command; - rh.stream_id = stream_id; - rh.length = payload_len; - relay_header_pack(cell.payload, &rh); - - if (payload_len) - memcpy(cell.payload+RELAY_HEADER_SIZE, payload, payload_len); - - /* Add random padding to the cell if we can. */ - pad_cell_payload(cell.payload, payload_len); - log_debug(LD_OR,"delivering %d cell %s.", relay_command, cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward"); @@ -744,7 +710,7 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *orig_circ, /* Let's assume we're well-behaved: Anything that we decide to send is * valid, delivered data. */ - circuit_sent_valid_data(origin_circ, rh.length); + circuit_sent_valid_data(origin_circ, msg_body_len); } int ret = circuit_package_relay_cell(&cell, circ, cell_direction, @@ -875,16 +841,16 @@ edge_reason_is_retriable(int reason) */ static int connection_ap_process_end_not_open( - relay_header_t *rh, cell_t *cell, origin_circuit_t *circ, + const relay_msg_t *msg, origin_circuit_t *circ, entry_connection_t *conn, crypt_path_t *layer_hint) { node_t *exitrouter; - int reason = *(cell->payload+RELAY_HEADER_SIZE); + int reason = get_uint8(msg->body); int control_reason; edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); (void) layer_hint; /* unused */ - if (rh->length > 0) { + if (msg->length > 0) { if (reason == END_STREAM_REASON_TORPROTOCOL || reason == END_STREAM_REASON_DESTROY) { /* Both of these reasons could mean a failed tag @@ -907,9 +873,9 @@ connection_ap_process_end_not_open( } /* This end cell is now valid. */ - circuit_read_valid_data(circ, rh->length); + circuit_read_valid_data(circ, msg->length); - if (rh->length == 0) { + if (msg->length == 0) { reason = END_STREAM_REASON_MISC; } @@ -928,19 +894,17 @@ connection_ap_process_end_not_open( case END_STREAM_REASON_EXITPOLICY: { tor_addr_t addr; tor_addr_make_unspec(&addr); - if (rh->length >= 5) { + if (msg->length >= 5) { int ttl = -1; tor_addr_make_unspec(&addr); - if (rh->length == 5 || rh->length == 9) { - tor_addr_from_ipv4n(&addr, - get_uint32(cell->payload+RELAY_HEADER_SIZE+1)); - if (rh->length == 9) - ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5)); - } else if (rh->length == 17 || rh->length == 21) { - tor_addr_from_ipv6_bytes(&addr, - (cell->payload+RELAY_HEADER_SIZE+1)); - if (rh->length == 21) - ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+17)); + if (msg->length == 5 || msg->length == 9) { + tor_addr_from_ipv4n(&addr, get_uint32(msg->body + 1)); + if (msg->length == 9) + ttl = (int)ntohl(get_uint32(msg->body + 5)); + } else if (msg->length == 17 || msg->length == 21) { + tor_addr_from_ipv6_bytes(&addr, msg->body + 1); + if (msg->length == 21) + ttl = (int)ntohl(get_uint32(msg->body + 17)); } if (tor_addr_is_null(&addr)) { log_info(LD_APP,"Address '%s' resolved to 0.0.0.0. Closing,", @@ -1062,7 +1026,7 @@ connection_ap_process_end_not_open( log_info(LD_APP, "Edge got end (%s) before we're connected. Marking for close.", - stream_end_reason_to_string(rh->length > 0 ? reason : -1)); + stream_end_reason_to_string(msg->length > 0 ? reason : -1)); circuit_log_path(LOG_INFO,LD_APP,circ); /* need to test because of detach_retriable */ if (!ENTRY_TO_CONN(conn)->marked_for_close) @@ -1135,17 +1099,17 @@ remap_event_helper(entry_connection_t *conn, const tor_addr_t *new_addr) * connection), and that the ttl can be absent (in which case <b>ttl_out</b> * is set to -1). */ STATIC int -connected_cell_parse(const relay_header_t *rh, const cell_t *cell, - tor_addr_t *addr_out, int *ttl_out) +connected_cell_parse(const relay_msg_t *msg, tor_addr_t *addr_out, + int *ttl_out) { uint32_t bytes; - const uint8_t *payload = cell->payload + RELAY_HEADER_SIZE; + const uint8_t *payload = msg->body; tor_addr_make_unspec(addr_out); *ttl_out = -1; - if (rh->length == 0) + if (msg->length == 0) return 0; - if (rh->length < 4) + if (msg->length < 4) return -1; bytes = ntohl(get_uint32(payload)); @@ -1153,13 +1117,13 @@ connected_cell_parse(const relay_header_t *rh, const cell_t *cell, if (bytes != 0) { /* v4 address */ tor_addr_from_ipv4h(addr_out, bytes); - if (rh->length >= 8) { + if (msg->length >= 8) { bytes = ntohl(get_uint32(payload + 4)); if (bytes <= INT32_MAX) *ttl_out = bytes; } } else { - if (rh->length < 25) /* 4 bytes of 0s, 1 addr, 16 ipv4, 4 ttl. */ + if (msg->length < 25) /* 4 bytes of 0s, 1 addr, 16 ipv4, 4 ttl. */ return -1; if (get_uint8(payload + 4) != 6) return -1; @@ -1187,8 +1151,8 @@ address_ttl_free_(address_ttl_t *addr) * one of 0, RESOLVED_TYPE_ERROR, or RESOLVED_TYPE_ERROR_TRANSIENT, and * return 0. */ STATIC int -resolved_cell_parse(const cell_t *cell, const relay_header_t *rh, - smartlist_t *addresses_out, int *errcode_out) +resolved_cell_parse(const relay_msg_t *msg, smartlist_t *addresses_out, + int *errcode_out) { const uint8_t *cp; uint8_t answer_type; @@ -1198,21 +1162,20 @@ resolved_cell_parse(const cell_t *cell, const relay_header_t *rh, int errcode = 0; smartlist_t *addrs; - tor_assert(cell); - tor_assert(rh); + tor_assert(msg); tor_assert(addresses_out); tor_assert(errcode_out); *errcode_out = 0; - if (rh->length > RELAY_PAYLOAD_SIZE) + if (msg->length > RELAY_PAYLOAD_SIZE_MAX) return -1; addrs = smartlist_new(); - cp = cell->payload + RELAY_HEADER_SIZE; + cp = msg->body; - remaining = rh->length; + remaining = msg->length; while (remaining) { const uint8_t *cp_orig = cp; if (remaining < 2) @@ -1359,8 +1322,7 @@ connection_ap_handshake_socks_got_resolved_cell(entry_connection_t *conn, * stream. */ STATIC int connection_edge_process_resolved_cell(edge_connection_t *conn, - const cell_t *cell, - const relay_header_t *rh) + const relay_msg_t *msg) { entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); smartlist_t *resolved_addresses = NULL; @@ -1374,7 +1336,7 @@ connection_edge_process_resolved_cell(edge_connection_t *conn, tor_assert(SOCKS_COMMAND_IS_RESOLVE(entry_conn->socks_request->command)); resolved_addresses = smartlist_new(); - if (resolved_cell_parse(cell, rh, resolved_addresses, &errcode)) { + if (resolved_cell_parse(msg, resolved_addresses, &errcode)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Dropping malformed 'resolved' cell"); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL); @@ -1407,7 +1369,7 @@ connection_edge_process_resolved_cell(edge_connection_t *conn, /* This is valid data at this point. Count it */ if (conn->on_circuit && CIRCUIT_IS_ORIGIN(conn->on_circuit)) { circuit_read_valid_data(TO_ORIGIN_CIRCUIT(conn->on_circuit), - rh->length); + msg->length); } connection_ap_handshake_socks_got_resolved_cell(entry_conn, @@ -1434,27 +1396,26 @@ connection_edge_process_resolved_cell(edge_connection_t *conn, */ static int connection_edge_process_relay_cell_not_open( - relay_header_t *rh, cell_t *cell, circuit_t *circ, + const relay_msg_t *msg, circuit_t *circ, edge_connection_t *conn, crypt_path_t *layer_hint) { - if (rh->command == RELAY_COMMAND_END) { + if (msg->command == RELAY_COMMAND_END) { if (CIRCUIT_IS_ORIGIN(circ) && conn->base_.type == CONN_TYPE_AP) { - return connection_ap_process_end_not_open(rh, cell, + return connection_ap_process_end_not_open(msg, TO_ORIGIN_CIRCUIT(circ), EDGE_TO_ENTRY_CONN(conn), layer_hint); } else { /* we just got an 'end', don't need to send one */ conn->edge_has_sent_end = 1; - conn->end_reason = *(cell->payload+RELAY_HEADER_SIZE) | - END_STREAM_REASON_FLAG_REMOTE; + conn->end_reason = get_uint8(msg->body) | END_STREAM_REASON_FLAG_REMOTE; connection_mark_for_close(TO_CONN(conn)); return 0; } } if (conn->base_.type == CONN_TYPE_AP && - rh->command == RELAY_COMMAND_CONNECTED) { + msg->command == RELAY_COMMAND_CONNECTED) { tor_addr_t addr; int ttl; entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); @@ -1469,9 +1430,9 @@ connection_edge_process_relay_cell_not_open( log_info(LD_APP,"'connected' received for circid %u streamid %d " "after %d seconds.", (unsigned)circ->n_circ_id, - rh->stream_id, + msg->stream_id, (int)(time(NULL) - conn->base_.timestamp_last_read_allowed)); - if (connected_cell_parse(rh, cell, &addr, &ttl) < 0) { + if (connected_cell_parse(msg, &addr, &ttl) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got a badly formatted connected cell. Closing."); connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); @@ -1549,7 +1510,7 @@ connection_edge_process_relay_cell_not_open( } /* This is valid data at this point. Count it */ - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); /* handle anything that might have queued */ if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) { @@ -1560,13 +1521,13 @@ connection_edge_process_relay_cell_not_open( return 0; } if (conn->base_.type == CONN_TYPE_AP && - rh->command == RELAY_COMMAND_RESOLVED) { - return connection_edge_process_resolved_cell(conn, cell, rh); + msg->command == RELAY_COMMAND_RESOLVED) { + return connection_edge_process_resolved_cell(conn, msg); } log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Got an unexpected relay command %d, in state %d (%s). Dropping.", - rh->command, conn->base_.state, + msg->command, conn->base_.state, conn_state_to_string(conn->base_.type, conn->base_.state)); return 0; /* for forward compatibility, don't kill the circuit */ // connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); @@ -1582,19 +1543,18 @@ connection_edge_process_relay_cell_not_open( * Return 0 if everything went well or a negative value representing a circuit * end reason on error for which the caller is responsible for closing it. */ static int -process_sendme_cell(const relay_header_t *rh, const cell_t *cell, - circuit_t *circ, edge_connection_t *conn, - crypt_path_t *layer_hint, int domain) +process_sendme_cell(const relay_msg_t *msg, circuit_t *circ, + edge_connection_t *conn, crypt_path_t *layer_hint, + int domain) { int ret; - tor_assert(rh); + tor_assert(msg); - if (!rh->stream_id) { + if (!msg->stream_id) { /* Circuit level SENDME cell. */ - ret = sendme_process_circuit_level(layer_hint, circ, - cell->payload + RELAY_HEADER_SIZE, - rh->length); + ret = sendme_process_circuit_level(layer_hint, circ, msg->body, + msg->length); if (ret < 0) { return ret; } @@ -1610,22 +1570,22 @@ process_sendme_cell(const relay_header_t *rh, const cell_t *cell, if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (connection_half_edge_is_valid_sendme(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); log_info(domain, "Sendme cell on circ %u valid on half-closed " "stream id %d", - ocirc->global_identifier, rh->stream_id); + ocirc->global_identifier, msg->stream_id); } } log_info(domain, "SENDME cell dropped, unknown stream (streamid %d).", - rh->stream_id); + msg->stream_id); return 0; } /* Stream level SENDME cell. */ // TODO: Turn this off for cc_alg=1,2,3; use XON/XOFF instead - ret = sendme_process_stream_level(conn, circ, rh->length); + ret = sendme_process_stream_level(conn, circ, msg->length); if (ret < 0) { /* Means we need to close the circuit with reason ret. */ return ret; @@ -1659,35 +1619,35 @@ process_sendme_cell(const relay_header_t *rh, const cell_t *cell, * parent function. */ STATIC int -handle_relay_cell_command(cell_t *cell, circuit_t *circ, - edge_connection_t *conn, crypt_path_t *layer_hint, - relay_header_t *rh, int optimistic_data) +handle_relay_msg(const relay_msg_t *msg, circuit_t *circ, + edge_connection_t *conn, crypt_path_t *layer_hint, + int optimistic_data) { unsigned domain = layer_hint?LD_APP:LD_EXIT; int reason; - tor_assert(rh); + tor_assert(msg); /* First pass the cell to the circuit padding subsystem, in case it's a * padding cell or circuit that should be handled there. */ - if (circpad_check_received_cell(cell, circ, layer_hint, rh) == 0) { + if (circpad_check_received_cell(msg, circ, layer_hint) == 0) { log_debug(domain, "Cell handled as circuit padding"); return 0; } /* Now handle all the other commands */ - switch (rh->command) { + switch (msg->command) { case RELAY_COMMAND_CONFLUX_LINK: - conflux_process_link(circ, cell, rh->length); + conflux_process_link(circ, msg); return 0; case RELAY_COMMAND_CONFLUX_LINKED: - conflux_process_linked(circ, layer_hint, cell, rh->length); + conflux_process_linked(circ, layer_hint, msg); return 0; case RELAY_COMMAND_CONFLUX_LINKED_ACK: conflux_process_linked_ack(circ); return 0; case RELAY_COMMAND_CONFLUX_SWITCH: - return conflux_process_switch_command(circ, layer_hint, cell, rh); + return conflux_process_switch_command(circ, layer_hint, msg); case RELAY_COMMAND_BEGIN: case RELAY_COMMAND_BEGIN_DIR: if (layer_hint && @@ -1708,7 +1668,7 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, "Begin cell for known stream. Dropping."); return 0; } - if (rh->command == RELAY_COMMAND_BEGIN_DIR && + if (msg->command == RELAY_COMMAND_BEGIN_DIR && circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) { /* Assign this circuit and its app-ward OR connection a unique ID, * so that we can measure download times. The local edge and dir @@ -1718,11 +1678,11 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, circ->dirreq_id = ++next_id; TO_OR_CIRCUIT(circ)->p_chan->dirreq_id = circ->dirreq_id; } - return connection_exit_begin_conn(cell, circ); + return connection_exit_begin_conn(msg, circ); case RELAY_COMMAND_DATA: ++stats_n_data_cells_received; - if (rh->stream_id == 0) { + if (msg->stream_id == 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay data cell with zero " "stream_id. Dropping."); return 0; @@ -1730,16 +1690,16 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (connection_half_edge_is_valid_data(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); log_info(domain, "data cell on circ %u valid on half-closed " - "stream id %d", ocirc->global_identifier, rh->stream_id); + "stream id %d", ocirc->global_identifier, msg->stream_id); } } log_info(domain,"data cell dropped, unknown stream (streamid %d).", - rh->stream_id); + msg->stream_id); return 0; } @@ -1753,20 +1713,19 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, return -END_CIRC_REASON_TORPROTOCOL; } /* Total all valid application bytes delivered */ - if (CIRCUIT_IS_ORIGIN(circ) && rh->length > 0) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + if (CIRCUIT_IS_ORIGIN(circ) && msg->length > 0) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } /* For onion service connection, update the metrics. */ if (conn->hs_ident) { hs_metrics_app_write_bytes(&conn->hs_ident->identity_pk, conn->hs_ident->orig_virtual_port, - rh->length); + msg->length); } - stats_n_data_bytes_received += rh->length; - connection_buf_add((char*)(cell->payload + RELAY_HEADER_SIZE), - rh->length, TO_CONN(conn)); + stats_n_data_bytes_received += msg->length; + connection_buf_add((char*) msg->body, msg->length, TO_CONN(conn)); #ifdef MEASUREMENTS_21206 /* Count number of RELAY_DATA cells received on a linked directory @@ -1792,16 +1751,16 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (relay_crypt_from_last_hop(ocirc, layer_hint) && connection_half_edge_is_valid_data(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); } } return 0; } - if (circuit_process_stream_xoff(conn, layer_hint, cell)) { + if (circuit_process_stream_xoff(conn, layer_hint)) { if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } } return 0; @@ -1811,35 +1770,34 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (relay_crypt_from_last_hop(ocirc, layer_hint) && connection_half_edge_is_valid_data(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); } } return 0; } - if (circuit_process_stream_xon(conn, layer_hint, cell)) { + if (circuit_process_stream_xon(conn, layer_hint, msg)) { if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } } return 0; case RELAY_COMMAND_END: - reason = rh->length > 0 ? - get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC; + reason = msg->length > 0 ? get_uint8(msg->body) : END_STREAM_REASON_MISC; if (!conn) { if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (relay_crypt_from_last_hop(ocirc, layer_hint) && connection_half_edge_is_valid_end(ocirc->half_streams, - rh->stream_id)) { + msg->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + circuit_read_valid_data(ocirc, msg->length); log_info(domain, "end cell (%s) on circ %u valid on half-closed " "stream id %d", stream_end_reason_to_string(reason), - ocirc->global_identifier, rh->stream_id); + ocirc->global_identifier, msg->stream_id); return 0; } } @@ -1871,7 +1829,7 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, /* Total all valid application bytes delivered */ if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } } return 0; @@ -1879,18 +1837,18 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, case RELAY_COMMAND_EXTEND2: { static uint64_t total_n_extend=0, total_nonearly=0; total_n_extend++; - if (rh->stream_id) { + if (msg->stream_id) { log_fn(LOG_PROTOCOL_WARN, domain, "'extend' cell received for non-zero stream. Dropping."); return 0; } - if (cell->command != CELL_RELAY_EARLY && + if (!msg->is_relay_early && !networkstatus_get_param(NULL,"AllowNonearlyExtend",0,0,1)) { #define EARLY_WARNING_INTERVAL 3600 static ratelim_t early_warning_limit = RATELIM_INIT(EARLY_WARNING_INTERVAL); char *m; - if (cell->command == CELL_RELAY) { + if (!msg->is_relay_early) { ++total_nonearly; if ((m = rate_limit_log(&early_warning_limit, approx_time()))) { double percentage = ((double)total_nonearly)/total_n_extend; @@ -1904,11 +1862,11 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, } else { log_fn(LOG_WARN, domain, "EXTEND cell received, in a cell with type %d! Dropping.", - cell->command); + msg->command); } return 0; } - return circuit_extend(cell, circ); + return circuit_extend(msg, circ); } case RELAY_COMMAND_EXTENDED: case RELAY_COMMAND_EXTENDED2: @@ -1920,9 +1878,8 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, log_debug(domain,"Got an extended cell! Yay."); { extended_cell_t extended_cell; - if (extended_cell_parse(&extended_cell, rh->command, - (const uint8_t*)cell->payload+RELAY_HEADER_SIZE, - rh->length)<0) { + if (extended_cell_parse(&extended_cell, msg->command, + msg->body, msg->length) < 0) { log_warn(LD_PROTOCOL, "Can't parse EXTENDED cell; killing circuit."); return -END_CIRC_REASON_TORPROTOCOL; @@ -1940,7 +1897,7 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, } /* Total all valid bytes delivered. */ if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } return 0; case RELAY_COMMAND_TRUNCATE: @@ -1958,7 +1915,7 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, circuit_set_state(circ, CIRCUIT_STATE_OPEN); } if (circ->n_chan) { - uint8_t trunc_reason = get_uint8(cell->payload + RELAY_HEADER_SIZE); + uint8_t trunc_reason = get_uint8(msg->body); circuit_synchronize_written_or_bandwidth(circ, CIRCUIT_N_CHAN); circuit_clear_cell_queue(circ, circ->n_chan); channel_send_destroy(circ->n_circ_id, circ->n_chan, @@ -1983,11 +1940,9 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, /* Count the truncated as valid, for completeness. The * circuit is being torn down anyway, though. */ if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), - rh->length); + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } - circuit_truncated(TO_ORIGIN_CIRCUIT(circ), - get_uint8(cell->payload + RELAY_HEADER_SIZE)); + circuit_truncated(TO_ORIGIN_CIRCUIT(circ), get_uint8(msg->body)); return 0; case RELAY_COMMAND_CONNECTED: if (conn) { @@ -1999,11 +1954,11 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (connection_half_edge_is_valid_connected(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); log_info(domain, "connected cell on circ %u valid on half-closed " - "stream id %d", ocirc->global_identifier, rh->stream_id); + "stream id %d", ocirc->global_identifier, msg->stream_id); return 0; } } @@ -2011,10 +1966,10 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, log_info(domain, "'connected' received on circid %u for streamid %d, " "no conn attached anymore. Ignoring.", - (unsigned)circ->n_circ_id, rh->stream_id); + (unsigned)circ->n_circ_id, msg->stream_id); return 0; case RELAY_COMMAND_SENDME: - return process_sendme_cell(rh, cell, circ, conn, layer_hint, domain); + return process_sendme_cell(msg, circ, conn, layer_hint, domain); case RELAY_COMMAND_RESOLVE: if (layer_hint) { log_fn(LOG_PROTOCOL_WARN, LD_APP, @@ -2030,7 +1985,7 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, circ->purpose); return 0; } - return connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ)); + return connection_exit_begin_resolve(msg, TO_OR_CIRCUIT(circ)); case RELAY_COMMAND_RESOLVED: if (conn) { log_fn(LOG_PROTOCOL_WARN, domain, @@ -2042,11 +1997,11 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (relay_crypt_from_last_hop(ocirc, layer_hint) && connection_half_edge_is_valid_resolved(ocirc->half_streams, - rh->stream_id)) { - circuit_read_valid_data(ocirc, rh->length); + msg->stream_id)) { + circuit_read_valid_data(ocirc, msg->length); log_info(domain, "resolved cell on circ %u valid on half-closed " - "stream id %d", ocirc->global_identifier, rh->stream_id); + "stream id %d", ocirc->global_identifier, msg->stream_id); return 0; } } @@ -2064,14 +2019,13 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, case RELAY_COMMAND_INTRO_ESTABLISHED: case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: rend_process_relay_cell(circ, layer_hint, - rh->command, rh->length, - cell->payload+RELAY_HEADER_SIZE); + msg->command, msg->length, msg->body); return 0; } log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received unknown relay command %d. Perhaps the other side is using " "a newer version of Tor? Dropping.", - rh->command); + msg->command); return 0; /* for forward compatibility, don't kill the circuit */ } @@ -2085,39 +2039,31 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ, * Return -reason if you want to warn and tear down the circuit, else 0. */ STATIC int -connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, +connection_edge_process_relay_cell(const relay_msg_t *msg, circuit_t *circ, edge_connection_t *conn, crypt_path_t *layer_hint) { static int num_seen=0; - relay_header_t rh; unsigned domain = layer_hint?LD_APP:LD_EXIT; - tor_assert(cell); + tor_assert(msg); tor_assert(circ); - relay_header_unpack(&rh, cell->payload); // log_fn(LOG_DEBUG,"command %d stream %d", rh.command, rh.stream_id); num_seen++; log_debug(domain, "Now seen %d relay cells here (command %d, stream %d).", - num_seen, rh.command, rh.stream_id); + num_seen, msg->command, msg->stream_id); - if (rh.length > RELAY_PAYLOAD_SIZE) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Relay cell length field too long. Closing circuit."); - return - END_CIRC_REASON_TORPROTOCOL; - } - - if (rh.stream_id == 0) { - switch (rh.command) { + if (msg->stream_id == 0) { + switch (msg->command) { case RELAY_COMMAND_BEGIN: case RELAY_COMMAND_CONNECTED: case RELAY_COMMAND_END: case RELAY_COMMAND_RESOLVE: case RELAY_COMMAND_RESOLVED: case RELAY_COMMAND_BEGIN_DIR: - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay command %d with zero " - "stream_id. Dropping.", (int)rh.command); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay command %u with zero " + "stream_id. Dropping.", msg->command); return 0; default: ; @@ -2127,7 +2073,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, /* Regardless of conflux or not, we always decide to send a SENDME * for RELAY_DATA immediately */ - if (rh.command == RELAY_COMMAND_DATA) { + if (msg->command == RELAY_COMMAND_DATA) { /* Update our circuit-level deliver window that we received a DATA cell. * If the deliver window goes below 0, we end the circuit and stream due * to a protocol failure. */ @@ -2151,37 +2097,39 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, * queues, and if doing so results in ordered cells to deliver, we * dequeue and process those in-order until there are no more. */ - if (!circ->conflux || !conflux_should_multiplex(rh.command)) { - return connection_edge_process_ordered_relay_cell(cell, circ, conn, - layer_hint, &rh); + if (!circ->conflux || !conflux_should_multiplex(msg->command)) { + return connection_edge_process_ordered_relay_cell(msg, circ, conn, + layer_hint); } else { // If conflux says this cell is in-order, then begin processing // cells from queue until there are none. Otherwise, we do nothing // until further cells arrive. - if (conflux_process_cell(circ->conflux, circ, layer_hint, cell)) { - conflux_cell_t *c_cell = NULL; + if (conflux_process_relay_msg(circ->conflux, circ, layer_hint, + (relay_msg_t *) msg)) { + conflux_msg_t *c_msg = NULL; int ret = 0; /* First, process this cell */ - if ((ret = connection_edge_process_ordered_relay_cell(cell, circ, conn, - layer_hint, &rh)) < 0) { + if ((ret = connection_edge_process_ordered_relay_cell(msg, circ, + conn, + layer_hint) < 0)) { return ret; } /* Now, check queue for more */ - while ((c_cell = conflux_dequeue_cell(circ->conflux))) { - relay_header_unpack(&rh, c_cell->cell.payload); - conn = relay_lookup_conn(circ, &c_cell->cell, CELL_DIRECTION_OUT, + while ((c_msg = conflux_dequeue_relay_msg(circ->conflux))) { + conn = relay_lookup_conn(circ, c_msg->msg, CELL_DIRECTION_OUT, layer_hint); - if ((ret = connection_edge_process_ordered_relay_cell(&c_cell->cell, - circ, conn, layer_hint, - &rh)) < 0) { + if ((ret = + connection_edge_process_ordered_relay_cell(c_msg->msg, circ, + conn, + layer_hint)) < 0) { /* Negative return value is a fatal error. Return early and tear down * circuit */ - tor_free(c_cell); + conflux_relay_msg_free(c_msg); return ret; } - tor_free(c_cell); + conflux_relay_msg_free(c_msg); } } } @@ -2193,17 +2141,17 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, * Helper function to process a relay cell that is in the proper order * for processing right now. */ static int -connection_edge_process_ordered_relay_cell(cell_t *cell, circuit_t *circ, +connection_edge_process_ordered_relay_cell(const relay_msg_t *msg, + circuit_t *circ, edge_connection_t *conn, - crypt_path_t *layer_hint, - relay_header_t *rh) + crypt_path_t *layer_hint) { int optimistic_data = 0; /* Set to 1 if we receive data on a stream * that's in the EXIT_CONN_STATE_RESOLVING * or EXIT_CONN_STATE_CONNECTING states. */ /* Tell circpad that we've received a recognized cell */ - circpad_deliver_recognized_relay_cell_events(circ, rh->command, layer_hint); + circpad_deliver_recognized_relay_cell_events(circ, msg->command, layer_hint); /* either conn is NULL, in which case we've got a control cell, or else * conn points to the recognized stream. */ @@ -2211,22 +2159,21 @@ connection_edge_process_ordered_relay_cell(cell_t *cell, circuit_t *circ, if (conn->base_.type == CONN_TYPE_EXIT && (conn->base_.state == EXIT_CONN_STATE_CONNECTING || conn->base_.state == EXIT_CONN_STATE_RESOLVING) && - rh->command == RELAY_COMMAND_DATA) { + msg->command == RELAY_COMMAND_DATA) { /* Allow DATA cells to be delivered to an exit node in state * EXIT_CONN_STATE_CONNECTING or EXIT_CONN_STATE_RESOLVING. * This speeds up HTTP, for example. */ optimistic_data = 1; - } else if (rh->stream_id == 0 && rh->command == RELAY_COMMAND_DATA) { + } else if (msg->stream_id == 0 && msg->command == RELAY_COMMAND_DATA) { log_warn(LD_BUG, "Somehow I had a connection that matched a " "data cell with stream ID 0."); } else { return connection_edge_process_relay_cell_not_open( - rh, cell, circ, conn, layer_hint); + msg, circ, conn, layer_hint); } } - return handle_relay_cell_command(cell, circ, conn, layer_hint, - rh, optimistic_data); + return handle_relay_msg(msg, circ, conn, layer_hint, optimistic_data); } /** How many relay_data cells have we built, ever? */ @@ -2257,20 +2204,14 @@ circuit_reset_sendme_randomness(circuit_t *circ) } /** - * Any relay data payload containing fewer than this many real bytes is - * considered to have enough randomness to. - **/ -#define RELAY_PAYLOAD_LENGTH_FOR_RANDOM_SENDMES \ - (RELAY_PAYLOAD_SIZE - CELL_PADDING_GAP - 16) - -/** * Helper. Return the number of bytes that should be put into a cell from a * given edge connection on which <b>n_available</b> bytes are available. */ STATIC size_t connection_edge_get_inbuf_bytes_to_package(size_t n_available, int package_partial, - circuit_t *on_circuit) + circuit_t *on_circuit, + crypt_path_t *cpath) { if (!n_available) return 0; @@ -2280,12 +2221,18 @@ connection_edge_get_inbuf_bytes_to_package(size_t n_available, (on_circuit->send_randomness_after_n_cells == 0) && (! on_circuit->have_sent_sufficiently_random_cell); - /* At most how much would we like to send in this cell? */ - size_t target_length; + relay_cell_fmt_t cell_format = circuit_get_relay_format(on_circuit, cpath); + size_t target_length = + relay_cell_max_payload_size(cell_format, RELAY_COMMAND_DATA); + +#define RELAY_CELL_PADDING_GAP 4 + + /* Any relay data payload containing fewer than this many real bytes is + * considered to have enough randomness to. */ + size_t target_length_with_random = target_length - + RELAY_CELL_PADDING_GAP - 16; if (force_random_bytes) { - target_length = RELAY_PAYLOAD_LENGTH_FOR_RANDOM_SENDMES; - } else { - target_length = RELAY_PAYLOAD_SIZE; + target_length = target_length_with_random; } /* Decide how many bytes we will actually put into this cell. */ @@ -2302,7 +2249,7 @@ connection_edge_get_inbuf_bytes_to_package(size_t n_available, /* If we reach this point, we will be definitely sending the cell. */ tor_assert_nonfatal(package_length > 0); - if (package_length <= RELAY_PAYLOAD_LENGTH_FOR_RANDOM_SENDMES) { + if (package_length <= target_length_with_random) { /* This cell will have enough randomness in the padding to make a future * sendme cell unpredictable. */ on_circuit->have_sent_sufficiently_random_cell = 1; @@ -2394,7 +2341,8 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, } length = connection_edge_get_inbuf_bytes_to_package(bytes_to_process, - package_partial, circ); + package_partial, circ, + cpath_layer); if (!length) return 0; @@ -3582,3 +3530,32 @@ circuit_queue_streams_are_blocked(circuit_t *circ) return circ->circuit_blocked_on_p_chan; } } + +/** Return the format to use. + * + * NULL can be passed but not for both. */ +relay_cell_fmt_t +circuit_get_relay_format(const circuit_t *circ, const crypt_path_t *cpath) +{ + if (circ && CIRCUIT_IS_ORCIRC(circ)) { + return CONST_TO_OR_CIRCUIT(circ)->relay_cell_format; + } else if (cpath) { + return cpath->relay_cell_format; + } else { + /* We end up here when both params are NULL, which is not allowed, or when + * only an origin circuit is given (which again is not allowed). */ + tor_assert_unreached(); + } +} + +/** + * Return the maximum relay payload that can be sent to the chosen + * point, with the specified command. + */ +size_t +circuit_max_relay_payload(const circuit_t *circ, const crypt_path_t *cpath, + uint8_t relay_command) +{ + relay_cell_fmt_t fmt = circuit_get_relay_format(circ, cpath); + return relay_cell_max_payload_size(fmt, relay_command); +} diff --git a/src/core/or/relay.h b/src/core/or/relay.h @@ -12,6 +12,8 @@ #ifndef TOR_RELAY_H #define TOR_RELAY_H +#include "core/or/relay_msg_st.h" + extern uint64_t stats_n_relay_cells_relayed; extern uint64_t stats_n_relay_cells_delivered; extern uint64_t stats_n_circ_max_cell_reached; @@ -26,8 +28,11 @@ int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, cell_direction_t cell_direction); size_t cell_queues_get_total_allocation(void); +#ifdef TOR_UNIT_TESTS void relay_header_pack(uint8_t *dest, const relay_header_t *src); void relay_header_unpack(relay_header_t *dest, const uint8_t *src); +#endif + MOCK_DECL(int, relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ, uint8_t relay_command, const char *payload, @@ -108,14 +113,20 @@ void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan); circid_t packed_cell_get_circid(const packed_cell_t *cell, int wide_circ_ids); uint8_t packed_cell_get_command(const packed_cell_t *cell, int wide_circ_ids); +relay_cell_fmt_t circuit_get_relay_format(const circuit_t *circ, + const crypt_path_t *cpath); +size_t circuit_max_relay_payload(const circuit_t *circ, + const crypt_path_t *cpath, + uint8_t relay_command); + #ifdef RELAY_PRIVATE STATIC int -handle_relay_cell_command(cell_t *cell, circuit_t *circ, - edge_connection_t *conn, crypt_path_t *layer_hint, - relay_header_t *rh, int optimistic_data); +handle_relay_msg(const relay_msg_t *msg, circuit_t *circ, + edge_connection_t *conn, crypt_path_t *layer_hint, + int optimistic_data); -STATIC int connected_cell_parse(const relay_header_t *rh, const cell_t *cell, - tor_addr_t *addr_out, int *ttl_out); +STATIC int connected_cell_parse(const relay_msg_t *msg, tor_addr_t *addr_out, + int *ttl_out); /** An address-and-ttl tuple as yielded by resolved_cell_parse */ typedef struct address_ttl_t { tor_addr_t addr; @@ -125,22 +136,22 @@ typedef struct address_ttl_t { STATIC void address_ttl_free_(address_ttl_t *addr); #define address_ttl_free(addr) \ FREE_AND_NULL(address_ttl_t, address_ttl_free_, (addr)) -STATIC int resolved_cell_parse(const cell_t *cell, const relay_header_t *rh, +STATIC int resolved_cell_parse(const relay_msg_t *msg, smartlist_t *addresses_out, int *errcode_out); STATIC int connection_edge_process_resolved_cell(edge_connection_t *conn, - const cell_t *cell, - const relay_header_t *rh); + const relay_msg_t *msg); STATIC packed_cell_t *packed_cell_new(void); STATIC packed_cell_t *cell_queue_pop(cell_queue_t *queue); STATIC destroy_cell_t *destroy_cell_queue_pop(destroy_cell_queue_t *queue); STATIC int cell_queues_check_size(void); -STATIC int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, - edge_connection_t *conn, - crypt_path_t *layer_hint); -STATIC size_t get_pad_cell_offset(size_t payload_len); +STATIC int connection_edge_process_relay_cell(const relay_msg_t *msg, + circuit_t *circ, + edge_connection_t *conn, + crypt_path_t *layer_hint); STATIC size_t connection_edge_get_inbuf_bytes_to_package(size_t n_available, int package_partial, - circuit_t *on_circuit); + circuit_t *on_circuit, + crypt_path_t *cpath); #endif /* defined(RELAY_PRIVATE) */ diff --git a/src/core/or/relay_msg.c b/src/core/or/relay_msg.c @@ -0,0 +1,286 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file relay_msg.c + * \brief Encoding relay messages into cells. + **/ + +#define RELAY_MSG_PRIVATE + +#include "app/config/config.h" + +#include "core/or/cell_st.h" +#include "core/or/circuitlist.h" +#include "core/or/relay.h" +#include "core/or/relay_msg.h" +#include "lib/crypt_ops/crypto_rand.h" + +#include "core/or/cell_st.h" +#include "core/or/relay_msg_st.h" +#include "core/or/crypt_path_st.h" +#include "core/or/or_circuit_st.h" + +/* + * Public API + */ + +/** Free the given relay message. */ +void +relay_msg_free_(relay_msg_t *msg) +{ + if (!msg) { + return; + } + tor_free(msg); +} + +/** Clear a relay message as in free its content and reset all fields to 0. + * This is useful for stack allocated memory. */ +void +relay_msg_clear(relay_msg_t *msg) +{ + tor_assert(msg); + memset(msg, 0, sizeof(*msg)); +} + +/* Positions of fields within a v0 message. */ +#define V0_CMD_OFFSET 0 +#define V0_STREAM_ID_OFFSET 3 +#define V0_LEN_OFFSET 9 +#define V0_PAYLOAD_OFFSET 11 + +/* Positions of fields within a v1 message. */ +#define V1_CMD_OFFSET 16 +#define V1_LEN_OFFSET 17 +#define V1_STREAM_ID_OFFSET 19 +#define V1_PAYLOAD_OFFSET_NO_STREAM_ID 19 +#define V1_PAYLOAD_OFFSET_WITH_STREAM_ID 21 + +/** Allocate a new relay message and copy the content of the given message. + * + * This message allocation _will_ own its body, even if the original did not. + * + * Requires that msg is well-formed, and that its length is within + * allowable bounds. + **/ +relay_msg_t * +relay_msg_copy(const relay_msg_t *msg) +{ + tor_assert(msg->length <= RELAY_PAYLOAD_SIZE_MAX); + void *alloc = tor_malloc_zero(sizeof(relay_msg_t) + msg->length); + relay_msg_t *new_msg = alloc; + uint8_t *body = ((uint8_t*)alloc) + sizeof(relay_msg_t); + + memcpy(new_msg, msg, sizeof(*msg)); + new_msg->body = body; + memcpy(body, msg->body, msg->length); + + return new_msg; +} + +/* Add random bytes to the unused portion of the payload, to foil attacks + * where the other side can predict all of the bytes in the payload and thus + * compute the authenticated SENDME cells without seeing the traffic. See + * proposal 289. */ +static void +relay_cell_pad(cell_t *cell, size_t end_of_message) +{ + // We add 4 bytes of zero before padding, for forward-compatibility. + const size_t skip = 4; + + if (end_of_message + skip >= CELL_PAYLOAD_SIZE) { + /* nothing to do. */ + return; + } + + crypto_fast_rng_getbytes(get_thread_fast_rng(), + &cell->payload[end_of_message + skip], + CELL_PAYLOAD_SIZE - (end_of_message + skip)); +} + +/** Encode the relay message in 'msg' into cell, according to the + * v0 rules. */ +static int +encode_v0_cell(const relay_msg_t *msg, + cell_t *cell_out) +{ + size_t maxlen = + relay_cell_max_payload_size(RELAY_CELL_FORMAT_V0, msg->command); + IF_BUG_ONCE(msg->length > maxlen) { + return -1; + } + + uint8_t *out = cell_out->payload; + + out[V0_CMD_OFFSET] = (uint8_t) msg->command; + set_uint16(out+V0_STREAM_ID_OFFSET, htons(msg->stream_id)); + set_uint16(out+V0_LEN_OFFSET, htons(msg->length)); + memcpy(out + RELAY_HEADER_SIZE_V0, msg->body, msg->length); + relay_cell_pad(cell_out, RELAY_HEADER_SIZE_V0 + msg->length); + + return 0; +} + +/** Encode the relay message in 'msg' into cell, according to the + * v0 rules. */ +static int +encode_v1_cell(const relay_msg_t *msg, + cell_t *cell_out) +{ + bool expects_streamid = relay_cmd_expects_streamid_in_v1(msg->command); + size_t maxlen = + relay_cell_max_payload_size(RELAY_CELL_FORMAT_V1, msg->command); + IF_BUG_ONCE(msg->length > maxlen) { + return -1; + } + + uint8_t *out = cell_out->payload; + out[V1_CMD_OFFSET] = msg->command; + set_uint16(out+V1_LEN_OFFSET, htons(msg->length)); + size_t payload_offset; + if (expects_streamid) { + IF_BUG_ONCE(msg->stream_id == 0) { + return -1; + } + set_uint16(out+V1_STREAM_ID_OFFSET, htons(msg->stream_id)); + payload_offset = V1_PAYLOAD_OFFSET_WITH_STREAM_ID; + } else { + IF_BUG_ONCE(msg->stream_id != 0) { + return -1; + } + + payload_offset = V1_PAYLOAD_OFFSET_NO_STREAM_ID; + } + + memcpy(out + payload_offset, msg->body, msg->length); + relay_cell_pad(cell_out, payload_offset + msg->length); + return 0; +} + +/** Try to decode 'cell' into a V0 relay message. + * + * Return 0 on success, -1 on error. + */ +static int +decode_v0_cell(const cell_t *cell, relay_msg_t *out) +{ + memset(out, 0, sizeof(relay_msg_t)); + out->is_relay_early = (cell->command == CELL_RELAY_EARLY); + + const uint8_t *body = cell->payload; + out->command = get_uint8(body + V0_CMD_OFFSET); + out->stream_id = ntohs(get_uint16(body + V0_STREAM_ID_OFFSET)); + out->length = ntohs(get_uint16(body + V0_LEN_OFFSET)); + + if (out->length > CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0) { + return -1; + } + out->body = body + V0_PAYLOAD_OFFSET; + + return 0; +} + +/** Try to decode 'cell' into a V1 relay message. + * + * Return 0 on success, -1 on error.= + */ +static int +decode_v1_cell(const cell_t *cell, relay_msg_t *out) +{ + memset(out, 0, sizeof(relay_msg_t)); + out->is_relay_early = (cell->command == CELL_RELAY_EARLY); + + const uint8_t *body = cell->payload; + out->command = get_uint8(body + V1_CMD_OFFSET); + if (! is_known_relay_command(out->command)) + return -1; + + out->length = ntohs(get_uint16(body + V1_LEN_OFFSET)); + size_t payload_offset; + if (relay_cmd_expects_streamid_in_v1(out->command)) { + out->stream_id = ntohs(get_uint16(body + V1_STREAM_ID_OFFSET)); + payload_offset = V1_PAYLOAD_OFFSET_WITH_STREAM_ID; + } else { + payload_offset = V1_PAYLOAD_OFFSET_NO_STREAM_ID; + } + + if (out->length > CELL_PAYLOAD_SIZE - payload_offset) + return -1; + out->body = body + payload_offset; + + return 0; +} +/** + * Encode 'msg' into 'cell' according to the rules of 'format'. + * + * Does not set any "recognized", "digest" or "tag" fields, + * since those are necessarily part of the crypto logic. + * + * Clears the circuit ID on the cell. + * + * Return 0 on success, and -1 if 'msg' is not well-formed. + */ +int +relay_msg_encode_cell(relay_cell_fmt_t format, + const relay_msg_t *msg, + cell_t *cell_out) +{ + memset(cell_out, 0, sizeof(cell_t)); + cell_out->command = msg->is_relay_early ? + CELL_RELAY_EARLY : CELL_RELAY; + + switch (format) { + case RELAY_CELL_FORMAT_V0: + return encode_v0_cell(msg, cell_out); + case RELAY_CELL_FORMAT_V1: + return encode_v1_cell(msg, cell_out); + default: + tor_fragile_assert(); + return -1; + } +} + +/** + * Decode 'cell' (which must be RELAY or RELAY_EARLY) into a newly allocated + * 'relay_msg_t'. + * + * Note that the resulting relay_msg_t will have a reference to 'cell'. + * Do not change 'cell' while the resulting message is still in use! + * + * Return -1 on error, and 0 on success. + */ +int +relay_msg_decode_cell_in_place(relay_cell_fmt_t format, + const cell_t *cell, + relay_msg_t *msg_out) +{ + switch (format) { + case RELAY_CELL_FORMAT_V0: + return decode_v0_cell(cell, msg_out); + case RELAY_CELL_FORMAT_V1: + return decode_v1_cell(cell, msg_out); + default: + tor_fragile_assert(); + return -1; + } +} + +/** + * As relay_msg_decode_cell_in_place, but allocate a new relay_msg_t + * on success. + * + * Return NULL on error. + */ +relay_msg_t * +relay_msg_decode_cell(relay_cell_fmt_t format, + const cell_t *cell) +{ + relay_msg_t *msg = tor_malloc(sizeof(relay_msg_t)); + if (relay_msg_decode_cell_in_place(format, cell, msg) < 0) { + relay_msg_free(msg); + return NULL; + } else { + return msg; + } +} diff --git a/src/core/or/relay_msg.h b/src/core/or/relay_msg.h @@ -0,0 +1,88 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file relay_msg.h + * \brief Header file for relay_msg.c. + **/ + +#ifndef TOR_RELAY_MSG_H +#define TOR_RELAY_MSG_H + +#include "core/or/or.h" + +#include "core/or/relay_msg_st.h" + +/* Relay message */ +void relay_msg_free_(relay_msg_t *msg); +void relay_msg_clear(relay_msg_t *msg); +relay_msg_t *relay_msg_copy(const relay_msg_t *msg); + +int relay_msg_encode_cell(relay_cell_fmt_t format, + const relay_msg_t *msg, + cell_t *cell_out) ATTR_WUR; +int relay_msg_decode_cell_in_place(relay_cell_fmt_t format, + const cell_t *cell, + relay_msg_t *msg_out) ATTR_WUR; +relay_msg_t *relay_msg_decode_cell( + relay_cell_fmt_t format, + const cell_t *cell) ATTR_WUR; + +#define relay_msg_free(msg) \ + FREE_AND_NULL(relay_msg_t, relay_msg_free_, (msg)) + +/* Getters */ + +/* + * NOTE: The following are inlined for performance reasons. These values are + * accessed everywhere and so, even if not expensive, we avoid a function call. + */ + +/** Return true iff 'cmd' uses a stream ID when using + * the v1 relay message format. */ +static bool +relay_cmd_expects_streamid_in_v1(uint8_t relay_command) +{ + switch (relay_command) { + case RELAY_COMMAND_BEGIN: + case RELAY_COMMAND_BEGIN_DIR: + case RELAY_COMMAND_CONNECTED: + case RELAY_COMMAND_DATA: + case RELAY_COMMAND_END: + case RELAY_COMMAND_RESOLVE: + case RELAY_COMMAND_RESOLVED: + case RELAY_COMMAND_XOFF: + case RELAY_COMMAND_XON: + return true; + default: + return false; + } +} + +/** Return the size of the relay cell payload for the given relay + * cell format. */ +static inline size_t +relay_cell_max_payload_size(relay_cell_fmt_t format, + uint8_t relay_command) +{ + switch (format) { + case RELAY_CELL_FORMAT_V0: + return CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0; + case RELAY_CELL_FORMAT_V1: { + if (relay_cmd_expects_streamid_in_v1(relay_command)) { + return CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID; + } else { + return CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_NO_STREAM_ID; + } + } + default: + tor_fragile_assert(); + return 0; + } +} + +#ifdef RELAY_MSG_PRIVATE + +#endif /* RELAY_MSG_PRIVATE */ + +#endif /* TOR_RELAY_MSG_H */ diff --git a/src/core/or/relay_msg_st.h b/src/core/or/relay_msg_st.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2023, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_msg_st.h + * @brief A relay message which contains a relay command and parameters, + * if any, that is from a relay cell. + **/ + +#ifndef TOR_RELAY_MSG_ST_H +#define TOR_RELAY_MSG_ST_H + +#include "core/or/or.h" + +/** A relay message object which contains pointers to the header and payload. + * + * One acquires a relay message through the use of an iterator. Once you get a + * reference, the getters MUST be used to access data. + * + * This CAN NOT be made opaque so to avoid heap allocation in the fast path. */ +typedef struct relay_msg_t { + /* Relay command of a message. */ + uint8_t command; + /* Length of the message body. + * + * This value MUST always be less than or equal to the lower of: + * - the number of bytes available in `body`. + * - relay_cell_max_format(_, command). + * + * (These bounds on the length field are guaranteed by all message decoding + * functions, and enforced by all message encoding functions.) + */ + uint16_t length; + /* Optional routing header: stream ID of a message or 0. */ + streamid_t stream_id; + /* Indicate if this is a message from a relay early cell. */ + bool is_relay_early; + /* Message body of a relay message. + * + * Code MUST NOT access any part of `body` beyond the first `length` bytes. + * + * NOTE that this struct does not own the body; instead, this is a pointer + * into a different object. */ + const uint8_t *body; +} relay_msg_t; + +#endif /* !defined(TOR_RELAY_MSG_ST_H) */ diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c @@ -229,7 +229,7 @@ sendme_is_valid(const circuit_t *circ, const uint8_t *cell_payload, } /* Build and encode a version 1 SENDME cell into payload, which must be at - * least of RELAY_PAYLOAD_SIZE bytes, using the digest for the cell data. + * least of RELAY_PAYLOAD_SIZE_MAX bytes, using the digest for the cell data. * * Return the size in bytes of the encoded cell in payload. A negative value * is returned on encoding failure. */ @@ -254,7 +254,7 @@ build_cell_payload_v1(const uint8_t *cell_digest, uint8_t *payload) sendme_cell_get_data_len(cell)); /* Finally, encode the cell into the payload. */ - len = sendme_cell_encode(payload, RELAY_PAYLOAD_SIZE, cell); + len = sendme_cell_encode(payload, RELAY_PAYLOAD_SIZE_MAX, cell); sendme_cell_free(cell); return len; @@ -270,7 +270,7 @@ send_circuit_level_sendme(circuit_t *circ, crypt_path_t *layer_hint, const uint8_t *cell_digest) { uint8_t emit_version; - uint8_t payload[RELAY_PAYLOAD_SIZE]; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX]; ssize_t payload_len; tor_assert(circ); diff --git a/src/core/or/status.c b/src/core/or/status.c @@ -221,10 +221,11 @@ log_heartbeat(time_t now) } double fullness_pct = 100; + // TODO CGO: This is slightly wrong? if (stats_n_data_cells_packaged && !hibernating) { fullness_pct = 100*(((double)stats_n_data_bytes_packaged) / - ((double)stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)); + ((double)stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE_MAX)); } const double overhead_pct = ( r - 1.0 ) * 100.0; diff --git a/src/feature/client/circpathbias.c b/src/feature/client/circpathbias.c @@ -34,10 +34,10 @@ #include "feature/client/entrynodes.h" #include "feature/nodelist/networkstatus.h" #include "core/or/relay.h" +#include "core/or/relay_msg.h" #include "lib/math/fp.h" #include "lib/math/laplace.h" -#include "core/or/cell_st.h" #include "core/or/cpath_build_state_st.h" #include "core/or/crypt_path_st.h" #include "core/or/extend_info_st.h" @@ -798,7 +798,7 @@ static int pathbias_send_usable_probe(circuit_t *circ) { /* Based on connection_ap_handshake_send_begin() */ - char payload[CELL_PAYLOAD_SIZE]; + char payload[RELAY_PAYLOAD_SIZE_MAX]; int payload_len; origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); crypt_path_t *cpath_layer = NULL; @@ -853,7 +853,7 @@ pathbias_send_usable_probe(circuit_t *circ) return -1; } - tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:25", probe_nonce); + tor_snprintf(payload,RELAY_PAYLOAD_SIZE_MAX, "%s:25", probe_nonce); payload_len = (int)strlen(payload)+1; // XXX: need this? Can we assume ipv4 will always be supported? @@ -903,41 +903,37 @@ pathbias_send_usable_probe(circuit_t *circ) * If the response is valid, return 0. Otherwise return < 0. */ int -pathbias_check_probe_response(circuit_t *circ, const cell_t *cell) +pathbias_check_probe_response(circuit_t *circ, const relay_msg_t *msg) { /* Based on connection_edge_process_relay_cell() */ - relay_header_t rh; int reason; uint32_t ipv4_host; origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); - tor_assert(cell); + tor_assert(msg); tor_assert(ocirc); tor_assert(circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING); - relay_header_unpack(&rh, cell->payload); + reason = msg->length > 0 ? get_uint8(msg->body) : END_STREAM_REASON_MISC; - reason = rh.length > 0 ? - get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC; - - if (rh.command == RELAY_COMMAND_END && + if (msg->command == RELAY_COMMAND_END && reason == END_STREAM_REASON_EXITPOLICY && - ocirc->pathbias_probe_id == rh.stream_id) { + ocirc->pathbias_probe_id == msg->stream_id) { /* Check length+extract host: It is in network order after the reason code. * See connection_edge_end(). */ - if (rh.length < 9) { /* reason+ipv4+dns_ttl */ + if (msg->length < 9) { /* reason+ipv4+dns_ttl */ log_notice(LD_PROTOCOL, - "Short path bias probe response length field (%d).", rh.length); + "Short path bias probe response length field (%d).", msg->length); return - END_CIRC_REASON_TORPROTOCOL; } - ipv4_host = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1)); + ipv4_host = ntohl(get_uint32(msg->body + 1)); /* Check nonce */ if (ipv4_host == ocirc->pathbias_probe_nonce) { pathbias_mark_use_success(ocirc); - circuit_read_valid_data(ocirc, rh.length); + circuit_read_valid_data(ocirc, msg->length); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); log_info(LD_CIRC, "Got valid path bias probe back for circ %d, stream %d.", @@ -954,7 +950,7 @@ pathbias_check_probe_response(circuit_t *circ, const cell_t *cell) log_info(LD_CIRC, "Got another cell back back on pathbias probe circuit %d: " "Command: %d, Reason: %d, Stream-id: %d", - ocirc->global_identifier, rh.command, reason, rh.stream_id); + ocirc->global_identifier, msg->command, reason, msg->stream_id); return -1; } @@ -963,58 +959,54 @@ pathbias_check_probe_response(circuit_t *circ, const cell_t *cell) * and if so, count it as valid. */ void -pathbias_count_valid_cells(circuit_t *circ, const cell_t *cell) +pathbias_count_valid_cells(circuit_t *circ, const relay_msg_t *msg) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); - relay_header_t rh; - - relay_header_unpack(&rh, cell->payload); /* Check to see if this is a cell from a previous connection, * or is a request to close the circuit. */ - switch (rh.command) { + switch (msg->command) { case RELAY_COMMAND_TRUNCATED: /* Truncated cells can arrive on path bias circs. When they do, * just process them. This closes the circ, but it was junk anyway. * No reason to wait for the probe. */ - circuit_read_valid_data(ocirc, rh.length); - circuit_truncated(TO_ORIGIN_CIRCUIT(circ), - get_uint8(cell->payload + RELAY_HEADER_SIZE)); + circuit_read_valid_data(ocirc, msg->length); + circuit_truncated(TO_ORIGIN_CIRCUIT(circ), get_uint8(msg->body)); break; case RELAY_COMMAND_END: if (connection_half_edge_is_valid_end(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); + msg->stream_id)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } break; case RELAY_COMMAND_DATA: if (connection_half_edge_is_valid_data(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); + msg->stream_id)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } break; case RELAY_COMMAND_SENDME: if (connection_half_edge_is_valid_sendme(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); + msg->stream_id)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } break; case RELAY_COMMAND_CONNECTED: if (connection_half_edge_is_valid_connected(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); + msg->stream_id)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } break; case RELAY_COMMAND_RESOLVED: if (connection_half_edge_is_valid_resolved(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); + msg->stream_id)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), msg->length); } break; } diff --git a/src/feature/client/circpathbias.h b/src/feature/client/circpathbias.h @@ -12,6 +12,8 @@ #ifndef TOR_CIRCPATHBIAS_H #define TOR_CIRCPATHBIAS_H +#include "core/or/relay_msg_st.h" + double pathbias_get_extreme_rate(const or_options_t *options); double pathbias_get_extreme_use_rate(const or_options_t *options); int pathbias_get_dropguards(const or_options_t *options); @@ -19,8 +21,8 @@ void pathbias_count_timeout(origin_circuit_t *circ); void pathbias_count_build_success(origin_circuit_t *circ); int pathbias_count_build_attempt(origin_circuit_t *circ); int pathbias_check_close(origin_circuit_t *circ, int reason); -int pathbias_check_probe_response(circuit_t *circ, const cell_t *cell); -void pathbias_count_valid_cells(circuit_t *circ, const cell_t *cell); +int pathbias_check_probe_response(circuit_t *circ, const relay_msg_t *msg); +void pathbias_count_valid_cells(circuit_t *circ, const relay_msg_t *msg); void pathbias_count_use_attempt(origin_circuit_t *circ); void pathbias_mark_use_success(origin_circuit_t *circ); void pathbias_mark_use_rollback(origin_circuit_t *circ); diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c @@ -41,7 +41,7 @@ compute_introduce_mac(const uint8_t *encoded_cell, size_t encoded_cell_len, { size_t offset = 0; size_t mac_msg_len; - uint8_t mac_msg[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t mac_msg[RELAY_PAYLOAD_SIZE_MAX] = {0}; tor_assert(encoded_cell); tor_assert(encrypted); @@ -299,8 +299,8 @@ introduce1_encrypt_and_encode(trn_cell_introduce1_t *cell, size_t offset = 0; ssize_t encrypted_len; ssize_t encoded_cell_len, encoded_enc_cell_len; - uint8_t encoded_cell[RELAY_PAYLOAD_SIZE] = {0}; - uint8_t encoded_enc_cell[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t encoded_cell[RELAY_PAYLOAD_SIZE_MAX] = {0}; + uint8_t encoded_enc_cell[RELAY_PAYLOAD_SIZE_MAX] = {0}; uint8_t *encrypted = NULL; uint8_t mac[DIGEST256_LEN]; crypto_cipher_t *cipher = NULL; @@ -339,7 +339,7 @@ introduce1_encrypt_and_encode(trn_cell_introduce1_t *cell, * ENCRYPTED_DATA and MAC length. */ encrypted_len = sizeof(data->client_kp->pubkey) + encoded_enc_cell_len + sizeof(mac); - tor_assert(encrypted_len < RELAY_PAYLOAD_SIZE); + tor_assert(encrypted_len < RELAY_PAYLOAD_SIZE_MAX); encrypted = tor_malloc_zero(encrypted_len); /* Put the CLIENT_PK first. */ @@ -709,7 +709,7 @@ hs_cell_build_establish_intro(const char *circ_nonce, ssize_t tmp_cell_mac_offset = sig_len + sizeof(cell->sig_len) + trn_cell_establish_intro_getlen_handshake_mac(cell); - uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE_MAX] = {0}; uint8_t mac[TRUNNEL_SHA3_256_LEN], *handshake_ptr; /* We first encode the current fields we have in the cell so we can @@ -738,7 +738,7 @@ hs_cell_build_establish_intro(const char *circ_nonce, { ssize_t tmp_cell_enc_len = 0; ssize_t tmp_cell_sig_offset = (sig_len + sizeof(cell->sig_len)); - uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0}, *sig_ptr; + uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE_MAX] = {0}, *sig_ptr; ed25519_signature_t sig; /* We first encode the current fields we have in the cell so we can @@ -764,7 +764,8 @@ hs_cell_build_establish_intro(const char *circ_nonce, } /* Encode the cell. Can't be bigger than a standard cell. */ - cell_len = trn_cell_establish_intro_encode(cell_out, RELAY_PAYLOAD_SIZE, + cell_len = trn_cell_establish_intro_encode(cell_out, + RELAY_PAYLOAD_SIZE_MAX, cell); done: @@ -1161,7 +1162,8 @@ hs_cell_build_rendezvous1(const uint8_t *rendezvous_cookie, memcpy(trn_cell_rendezvous1_getarray_handshake_info(cell), rendezvous_handshake_info, rendezvous_handshake_info_len); /* Encoding. */ - cell_len = trn_cell_rendezvous1_encode(cell_out, RELAY_PAYLOAD_SIZE, cell); + cell_len = trn_cell_rendezvous1_encode(cell_out, + RELAY_PAYLOAD_SIZE_MAX, cell); tor_assert(cell_len > 0); trn_cell_rendezvous1_free(cell); @@ -1200,7 +1202,8 @@ hs_cell_build_introduce1(const hs_cell_introduce1_data_t *data, introduce1_set_encrypted(cell, data); /* Final encoding. */ - cell_len = trn_cell_introduce1_encode(cell_out, RELAY_PAYLOAD_SIZE, cell); + cell_len = trn_cell_introduce1_encode(cell_out, + RELAY_PAYLOAD_SIZE_MAX, cell); trn_cell_introduce1_free(cell); return cell_len; diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c @@ -110,6 +110,9 @@ create_rend_cpath(const uint8_t *ntor_key_seed, size_t seed_len, cpath = tor_malloc_zero(sizeof(crypt_path_t)); cpath->magic = CRYPT_PATH_MAGIC; + // TODO CGO: Pick relay cell format based on capabilities. + cpath->relay_cell_format = RELAY_CELL_FORMAT_V0; + if (cpath_init_circuit_crypto(cpath, (char*)keys, sizeof(keys), is_service_side, 1) < 0) { tor_free(cpath); @@ -268,7 +271,7 @@ send_establish_intro(const hs_service_t *service, hs_service_intro_point_t *ip, origin_circuit_t *circ) { ssize_t cell_len; - uint8_t payload[RELAY_PAYLOAD_SIZE]; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX]; tor_assert(service); tor_assert(ip); @@ -1153,7 +1156,7 @@ hs_circ_service_rp_has_opened(const hs_service_t *service, origin_circuit_t *circ) { size_t payload_len; - uint8_t payload[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; tor_assert(service); tor_assert(circ); @@ -1442,7 +1445,7 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ, { int ret = -1; ssize_t payload_len; - uint8_t payload[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t payload[RELAY_PAYLOAD_SIZE_MAX] = {0}; hs_cell_introduce1_data_t intro1_data; tor_assert(intro_circ); @@ -1526,7 +1529,7 @@ int hs_circ_send_establish_rendezvous(origin_circuit_t *circ) { ssize_t cell_len = 0; - uint8_t cell[RELAY_PAYLOAD_SIZE] = {0}; + uint8_t cell[RELAY_PAYLOAD_SIZE_MAX] = {0}; tor_assert(circ); tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c @@ -421,15 +421,14 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec, * Return -1 if we want to warn and tear down the circuit, else return 0. */ int -circuit_extend(struct cell_t *cell, struct circuit_t *circ) +circuit_extend(const relay_msg_t *rmsg, struct circuit_t *circ) { channel_t *n_chan; - relay_header_t rh; extend_cell_t ec; const char *msg = NULL; int should_launch = 0; - IF_BUG_ONCE(!cell) { + IF_BUG_ONCE(!rmsg) { return -1; } @@ -440,17 +439,13 @@ circuit_extend(struct cell_t *cell, struct circuit_t *circ) if (circuit_extend_state_valid_helper(circ) < 0) return -1; - relay_header_unpack(&rh, cell->payload); - /* We no longer accept EXTEND messages; only EXTEND2. */ - if (rh.command == RELAY_COMMAND_EXTEND) { + if (rmsg->command == RELAY_COMMAND_EXTEND) { /* TODO: Should we log this? */ return -1; } - if (extend_cell_parse(&ec, rh.command, - cell->payload+RELAY_HEADER_SIZE, - rh.length) < 0) { + if (extend_cell_parse(&ec, rmsg->command, rmsg->body, rmsg->length) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Can't parse extend cell. Closing circuit."); return -1; diff --git a/src/feature/relay/circuitbuild_relay.h b/src/feature/relay/circuitbuild_relay.h @@ -14,6 +14,7 @@ #include "lib/cc/torint.h" #include "lib/log/log.h" +#include "core/or/relay_msg_st.h" #include "app/config/config.h" @@ -34,7 +35,7 @@ circuitbuild_warn_client_extend(void) #ifdef HAVE_MODULE_RELAY -int circuit_extend(struct cell_t *cell, struct circuit_t *circ); +int circuit_extend(const relay_msg_t *msg, struct circuit_t *circ); int onionskin_answer(struct or_circuit_t *circ, const struct created_cell_t *created_cell, @@ -44,9 +45,9 @@ int onionskin_answer(struct or_circuit_t *circ, #else /* !defined(HAVE_MODULE_RELAY) */ static inline int -circuit_extend(struct cell_t *cell, struct circuit_t *circ) +circuit_extend(const relay_msg_t *msg, struct circuit_t *circ) { - (void)cell; + (void)msg; (void)circ; circuitbuild_warn_client_extend(); return -1; diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c @@ -508,7 +508,9 @@ MOCK_IMPL(STATIC void, send_resolved_cell,(edge_connection_t *conn, uint8_t answer_type, const cached_resolve_t *resolved)) { - char buf[RELAY_PAYLOAD_SIZE], *cp = buf; + // (We use the minimum here to ensure that we never + // generate a too-big message.) + char buf[RELAY_PAYLOAD_SIZE_MIN], *cp = buf; size_t buflen = 0; uint32_t ttl; @@ -581,7 +583,7 @@ MOCK_IMPL(STATIC void, send_resolved_hostname_cell,(edge_connection_t *conn, const char *hostname)) { - char buf[RELAY_PAYLOAD_SIZE]; + char buf[RELAY_PAYLOAD_SIZE_MAX]; size_t buflen; uint32_t ttl; @@ -590,7 +592,9 @@ send_resolved_hostname_cell,(edge_connection_t *conn, size_t namelen = strlen(hostname); - tor_assert(namelen < 256); + if (BUG(namelen >= 256)) { + return; + } ttl = conn->address_ttl; buf[0] = RESOLVED_TYPE_HOSTNAME; diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c @@ -17,9 +17,11 @@ #include "core/crypto/onion_fast.h" #include "core/crypto/onion_ntor.h" #include "core/or/relay.h" +#include "core/or/relay_msg.h" #include "core/or/cell_st.h" #include "core/or/cell_queue_st.h" +#include "core/or/relay_msg_st.h" #include "core/or/var_cell_st.h" #include "test/test.h" @@ -31,12 +33,12 @@ static void test_cfmt_relay_header(void *arg) { relay_header_t rh; - const uint8_t hdr_1[RELAY_HEADER_SIZE] = + const uint8_t hdr_1[RELAY_HEADER_SIZE_V0] = "\x03" "\x00\x00" "\x21\x22" "ABCD" "\x01\x03"; - uint8_t hdr_out[RELAY_HEADER_SIZE]; + uint8_t hdr_out[RELAY_HEADER_SIZE_V0]; (void)arg; - tt_int_op(sizeof(hdr_1), OP_EQ, RELAY_HEADER_SIZE); + tt_int_op(sizeof(hdr_1), OP_EQ, RELAY_HEADER_SIZE_V0); relay_header_unpack(&rh, hdr_1); tt_int_op(rh.command, OP_EQ, 3); tt_int_op(rh.recognized, OP_EQ, 0); @@ -45,42 +47,35 @@ test_cfmt_relay_header(void *arg) tt_int_op(rh.length, OP_EQ, 0x103); relay_header_pack(hdr_out, &rh); - tt_mem_op(hdr_out, OP_EQ, hdr_1, RELAY_HEADER_SIZE); + tt_mem_op(hdr_out, OP_EQ, hdr_1, RELAY_HEADER_SIZE_V0); done: ; } static void -make_relay_cell(cell_t *out, uint8_t command, - const void *body, size_t bodylen) +make_relay_msg(relay_msg_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); + memset(out, 0, sizeof(*out)); + out->command = command; + out->body = (uint8_t *)body; + out->length = bodylen; + out->stream_id = 5; } static void test_cfmt_begin_cells(void *arg) { - cell_t cell; + relay_msg_t msg; begin_cell_t bcell; uint8_t end_reason; (void)arg; /* Try begindir. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "", 0); - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN_DIR, "", 0); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_ptr_op(NULL, OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(0, OP_EQ, bcell.port); @@ -89,8 +84,8 @@ test_cfmt_begin_cells(void *arg) /* A Begindir with extra stuff. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "12345", 5); - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN_DIR, "12345", 5); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_ptr_op(NULL, OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(0, OP_EQ, bcell.port); @@ -99,8 +94,8 @@ test_cfmt_begin_cells(void *arg) /* A short but valid begin cell */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:9", 6); - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:9", 6); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_str_op("a.b", OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(9, OP_EQ, bcell.port); @@ -111,21 +106,21 @@ test_cfmt_begin_cells(void *arg) /* A significantly loner begin cell */ memset(&bcell, 0x7f, sizeof(bcell)); { - const char c[] = "here-is-a-nice-long.hostname.com:65535"; - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, strlen(c)+1); - } - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + const char c[] = "here-is-a-nice-long.hostname.com:65535"; + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, c, strlen(c)+1); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_str_op("here-is-a-nice-long.hostname.com", OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(65535, OP_EQ, bcell.port); tt_int_op(5, OP_EQ, bcell.stream_id); tt_int_op(0, OP_EQ, bcell.is_begindir); tor_free(bcell.address); + } /* An IPv4 begin cell. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "18.9.22.169:80", 15); - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "18.9.22.169:80", 15); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_str_op("18.9.22.169", OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(80, OP_EQ, bcell.port); @@ -135,9 +130,9 @@ test_cfmt_begin_cells(void *arg) /* An IPv6 begin cell. Let's make sure we handle colons*/ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "[2620::6b0:b:1a1a:0:26e5:480e]:80", 34); - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); tt_str_op("[2620::6b0:b:1a1a:0:26e5:480e]", OP_EQ, bcell.address); tt_int_op(0, OP_EQ, bcell.flags); tt_int_op(80, OP_EQ, bcell.port); @@ -149,88 +144,85 @@ test_cfmt_begin_cells(void *arg) memset(&bcell, 0x7f, sizeof(bcell)); { const char c[] = "another.example.com:80\x00\x01\x02"; - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); + tt_str_op("another.example.com", OP_EQ, bcell.address); + tt_int_op(0, OP_EQ, bcell.flags); + tt_int_op(80, OP_EQ, bcell.port); + tt_int_op(5, OP_EQ, bcell.stream_id); + tt_int_op(0, OP_EQ, bcell.is_begindir); + tor_free(bcell.address); } - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); - tt_str_op("another.example.com", OP_EQ, bcell.address); - tt_int_op(0, OP_EQ, bcell.flags); - tt_int_op(80, OP_EQ, bcell.port); - tt_int_op(5, OP_EQ, bcell.stream_id); - tt_int_op(0, OP_EQ, bcell.is_begindir); - tor_free(bcell.address); /* a begin cell with flags. */ memset(&bcell, 0x7f, sizeof(bcell)); { const char c[] = "another.example.com:443\x00\x01\x02\x03\x04"; - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); + tt_str_op("another.example.com", OP_EQ, bcell.address); + tt_int_op(0x1020304, OP_EQ, bcell.flags); + tt_int_op(443, OP_EQ, bcell.port); + tt_int_op(5, OP_EQ, bcell.stream_id); + tt_int_op(0, OP_EQ, bcell.is_begindir); + tor_free(bcell.address); } - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); - tt_str_op("another.example.com", OP_EQ, bcell.address); - tt_int_op(0x1020304, OP_EQ, bcell.flags); - tt_int_op(443, OP_EQ, bcell.port); - tt_int_op(5, OP_EQ, bcell.stream_id); - tt_int_op(0, OP_EQ, bcell.is_begindir); - tor_free(bcell.address); /* a begin cell with flags and even more cruft after that. */ memset(&bcell, 0x7f, sizeof(bcell)); { const char c[] = "a-further.example.com:22\x00\xee\xaa\x00\xffHi mom"; - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); + tt_int_op(0, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); + tt_str_op("a-further.example.com", OP_EQ, bcell.address); + tt_int_op(0xeeaa00ff, OP_EQ, bcell.flags); + tt_int_op(22, OP_EQ, bcell.port); + tt_int_op(5, OP_EQ, bcell.stream_id); + tt_int_op(0, OP_EQ, bcell.is_begindir); + tor_free(bcell.address); } - tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); - tt_str_op("a-further.example.com", OP_EQ, bcell.address); - tt_int_op(0xeeaa00ff, OP_EQ, bcell.flags); - tt_int_op(22, OP_EQ, bcell.port); - tt_int_op(5, OP_EQ, bcell.stream_id); - tt_int_op(0, OP_EQ, bcell.is_begindir); - tor_free(bcell.address); +#if 0 + // Note: This is now checked at when we decode the relay message. /* bad begin cell: impossible length. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 7); - cell.payload[9] = 0x01; /* Set length to 510 */ - cell.payload[10] = 0xfe; - { - relay_header_t rh; - relay_header_unpack(&rh, cell.payload); - tt_int_op(rh.length, OP_EQ, 510); - } - tt_int_op(-2, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:80", 7); + msg.length = 510; + tt_int_op(-2, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); +#endif /* Bad begin cell: no body. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "", 0); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); /* bad begin cell: no body. */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "", 0); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); /* bad begin cell: no colon */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b", 4); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b", 4); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); /* bad begin cell: no ports */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:", 5); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:", 5); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); /* bad begin cell: bad port */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:xyz", 8); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:xyz", 8); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:100000", 11); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:100000", 11); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); /* bad begin cell: no nul */ memset(&bcell, 0x7f, sizeof(bcell)); - make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 6); - tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason)); + make_relay_msg(&msg, RELAY_COMMAND_BEGIN, "a.b:80", 6); + tt_int_op(-1, OP_EQ, begin_cell_parse(&msg, &bcell, &end_reason)); done: tor_free(bcell.address); @@ -239,144 +231,129 @@ test_cfmt_begin_cells(void *arg) static void test_cfmt_connected_cells(void *arg) { - relay_header_t rh; - cell_t cell; tor_addr_t addr; int ttl, r; char *mem_op_hex_tmp = NULL; + relay_msg_t msg; + uint8_t buf[512]; (void)arg; /* Let's try an oldschool one with nothing in it. */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "", 0); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "", 0); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_UNSPEC); tt_int_op(ttl, OP_EQ, -1); /* A slightly less oldschool one: only an IPv4 address */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x20\x30\x40\x50", 4); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x20\x30\x40\x50", 4); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET); tt_str_op(fmt_addr(&addr), OP_EQ, "32.48.64.80"); tt_int_op(ttl, OP_EQ, -1); /* Bogus but understandable: truncated TTL */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x11\x12\x13\x14\x15", 5); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x11\x12\x13\x14\x15", 5); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET); tt_str_op(fmt_addr(&addr), OP_EQ, "17.18.19.20"); tt_int_op(ttl, OP_EQ, -1); /* Regular IPv4 one: address and TTL */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x02\x03\x04\x05\x00\x00\x0e\x10", 8); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET); tt_str_op(fmt_addr(&addr), OP_EQ, "2.3.4.5"); tt_int_op(ttl, OP_EQ, 3600); /* IPv4 with too-big TTL */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x02\x03\x04\x05\xf0\x00\x00\x00", 8); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET); tt_str_op(fmt_addr(&addr), OP_EQ, "2.3.4.5"); tt_int_op(ttl, OP_EQ, -1); /* IPv6 (ttl is mandatory) */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x06" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x00\x00\x02\x58", 25); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET6); tt_str_op(fmt_addr(&addr), OP_EQ, "2607:f8b0:400c:c02::68"); tt_int_op(ttl, OP_EQ, 600); /* IPv6 (ttl too big) */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x06" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x90\x00\x02\x58", 25); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET6); tt_str_op(fmt_addr(&addr), OP_EQ, "2607:f8b0:400c:c02::68"); tt_int_op(ttl, OP_EQ, -1); /* Bogus size: 3. */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x00\x01\x02", 3); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, -1); /* Bogus family: 7. */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x07" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x90\x00\x02\x58", 25); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, -1); /* Truncated IPv6. */ - make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, + make_relay_msg(&msg, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x06" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x00\x00\x02", 24); - relay_header_unpack(&rh, cell.payload); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, -1); /* Now make sure we can generate connected cells correctly. */ /* Try an IPv4 address */ - memset(&rh, 0, sizeof(rh)); - memset(&cell, 0, sizeof(cell)); tor_addr_parse(&addr, "30.40.50.60"); - rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE, - &addr, 1024); - tt_int_op(rh.length, OP_EQ, 8); - test_memeq_hex(cell.payload+RELAY_HEADER_SIZE, "1e28323c" "00000400"); + msg.body = buf; + msg.length = connected_cell_format_payload(buf, &addr, 1024); + tt_int_op(msg.length, OP_EQ, 8); + test_memeq_hex(msg.body, "1e28323c" "00000400"); /* Try parsing it. */ tor_addr_make_unspec(&addr); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET); tt_str_op(fmt_addr(&addr), OP_EQ, "30.40.50.60"); tt_int_op(ttl, OP_EQ, 1024); /* Try an IPv6 address */ - memset(&rh, 0, sizeof(rh)); - memset(&cell, 0, sizeof(cell)); tor_addr_parse(&addr, "2620::6b0:b:1a1a:0:26e5:480e"); - rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE, - &addr, 3600); - tt_int_op(rh.length, OP_EQ, 25); - test_memeq_hex(cell.payload + RELAY_HEADER_SIZE, + msg.length = connected_cell_format_payload(buf, &addr, 3600); + tt_int_op(msg.length, OP_EQ, 25); + test_memeq_hex(msg.body, "00000000" "06" "2620000006b0000b1a1a000026e5480e" "00000e10"); /* Try parsing it. */ tor_addr_make_unspec(&addr); - r = connected_cell_parse(&rh, &cell, &addr, &ttl); + r = connected_cell_parse(&msg, &addr, &ttl); tt_int_op(r, OP_EQ, 0); tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET6); tt_str_op(fmt_addr(&addr), OP_EQ, "2620:0:6b0:b:1a1a:0:26e5:480e"); @@ -518,11 +495,11 @@ test_cfmt_created_cells(void *arg) memset(b, 0, sizeof(b)); crypto_rand((char*)b, 496); cell.command = CELL_CREATED2; - memcpy(cell.payload, "\x01\xF1", 2); + memcpy(cell.payload, "\x02\xFF", 2); tt_int_op(-1, OP_EQ, created_cell_parse(&cc, &cell)); /* Unformattable CREATED2 cell: too long! */ - cc.handshake_len = 497; + cc.handshake_len = 508; tt_int_op(-1, OP_EQ, created_cell_format(&cell2, &cc)); done: @@ -823,15 +800,15 @@ static void test_cfmt_resolved_cells(void *arg) { smartlist_t *addrs = smartlist_new(); - relay_header_t rh; - cell_t cell; int r, errcode; address_ttl_t *a; + relay_msg_t msg; + uint8_t buf[500]; (void)arg; #define CLEAR_CELL() do { \ - memset(&cell, 0, sizeof(cell)); \ - memset(&rh, 0, sizeof(rh)); \ + memset(&msg, 0, sizeof(msg)); \ + memset(&buf, 0, sizeof(buf)); \ } while (0) #define CLEAR_ADDRS() do { \ SMARTLIST_FOREACH(addrs, address_ttl_t *, aa_, \ @@ -840,9 +817,10 @@ test_cfmt_resolved_cells(void *arg) } while (0) #define SET_CELL(s) do { \ CLEAR_CELL(); \ - memcpy(cell.payload + RELAY_HEADER_SIZE, (s), sizeof((s))-1); \ - rh.length = sizeof((s))-1; \ - rh.command = RELAY_COMMAND_RESOLVED; \ + memcpy(buf, (s), sizeof((s))-1); \ + msg.length = sizeof((s))-1; \ + msg.body = buf; \ + msg.command = RELAY_COMMAND_RESOLVED; \ errcode = -1; \ } while (0) @@ -855,7 +833,7 @@ test_cfmt_resolved_cells(void *arg) /* Let's try an empty cell */ SET_CELL(""); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -863,8 +841,8 @@ test_cfmt_resolved_cells(void *arg) /* Cell with one ipv4 addr */ SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"); - tt_int_op(rh.length, OP_EQ, 10); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 10); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 1); @@ -879,8 +857,8 @@ test_cfmt_resolved_cells(void *arg) "\x20\x02\x90\x90\x00\x00\x00\x00" "\x00\x00\x00\x00\xf0\xf0\xab\xcd" "\x02\00\x00\x01"); - tt_int_op(rh.length, OP_EQ, 22); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 22); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 1); @@ -894,8 +872,8 @@ test_cfmt_resolved_cells(void *arg) SET_CELL("\x00\x11" "motherbrain.zebes" "\x00\00\x00\x00"); - tt_int_op(rh.length, OP_EQ, 23); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 23); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 1); @@ -915,8 +893,8 @@ test_cfmt_resolved_cells(void *arg) SET_CELL("\x00\xff" LONG_NAME "\x00\01\x00\x00"); - tt_int_op(rh.length, OP_EQ, 261); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 261); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 1); @@ -930,8 +908,8 @@ test_cfmt_resolved_cells(void *arg) SET_CELL("\xf0\x2b" "I'm sorry, Dave. I'm afraid I can't do that" "\x00\x11\x22\x33"); - tt_int_op(rh.length, OP_EQ, 49); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 49); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, RESOLVED_TYPE_ERROR_TRANSIENT); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -940,8 +918,8 @@ test_cfmt_resolved_cells(void *arg) SET_CELL("\xf1\x40" "This hostname is too important for me to allow you to resolve it" "\x00\x00\x00\x00"); - tt_int_op(rh.length, OP_EQ, 70); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 70); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, RESOLVED_TYPE_ERROR); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -951,8 +929,8 @@ test_cfmt_resolved_cells(void *arg) SET_CELL("\xee\x16" "fault in the AE35 unit" "\x09\x09\x01\x01"); - tt_int_op(rh.length, OP_EQ, 28); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, 28); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -979,7 +957,7 @@ test_cfmt_resolved_cells(void *arg) "motherbrain.zebes" "\x00\00\x00\x00" ); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); /* no error reported; we got answers */ tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 3); @@ -1011,7 +989,7 @@ test_cfmt_resolved_cells(void *arg) "\x20\x02\x90\x01\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\xfa\xca\xde" "\x00\00\x00\x03"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 5); @@ -1051,8 +1029,8 @@ test_cfmt_resolved_cells(void *arg) "\x00\xe7" LONG_NAME2 "\x00\01\x00\x00"); - tt_int_op(rh.length, OP_EQ, RELAY_PAYLOAD_SIZE); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + tt_int_op(msg.length, OP_EQ, RELAY_PAYLOAD_SIZE); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, 0); tt_int_op(smartlist_len(addrs), OP_EQ, 2); @@ -1066,68 +1044,71 @@ test_cfmt_resolved_cells(void *arg) /* Invalid length on an IPv4 */ SET_CELL("\x04\x03zzz1234"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" "\x04\x05zzzzz1234"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); /* Invalid length on an IPv6 */ SET_CELL("\x06\x03zzz1234"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" "\x06\x17wwwwwwwwwwwwwwwww1234"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00" "\x06\x10xxxx"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); /* Empty hostname */ SET_CELL("\x00\x00xxxx"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); +#if 0 + //No longer possible with relay message encoding. /* rh.length out of range */ CLEAR_CELL(); rh.length = 499; - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(errcode, OP_EQ, 0); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); +#endif /* Item length extends beyond rh.length */ CLEAR_CELL(); SET_CELL("\x00\xff" LONG_NAME "\x00\01\x00\x00"); - rh.length -= 1; - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + msg.length -= 1; + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); - rh.length -= 5; - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + msg.length -= 5; + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"); - rh.length -= 1; - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + msg.length -= 1; + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -1135,19 +1116,19 @@ test_cfmt_resolved_cells(void *arg) "\x20\x02\x90\x01\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\xfa\xca\xde" "\x00\00\x00\x03"); - rh.length -= 1; - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + msg.length -= 1; + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); /* Truncated item after first character */ SET_CELL("\x04"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); SET_CELL("\xee"); - r = resolved_cell_parse(&cell, &rh, addrs, &errcode); + r = resolved_cell_parse(&msg, addrs, &errcode); tt_int_op(r, OP_EQ, -1); tt_int_op(smartlist_len(addrs), OP_EQ, 0); @@ -1200,6 +1181,419 @@ test_cfmt_is_destroy(void *arg) tor_free(chan); } +static void +test_cfmt_relay_msg_encoding_simple(void *arg) +{ + (void)arg; + relay_msg_t *msg1 = NULL; + cell_t cell; + char *mem_op_hex_tmp = NULL; + int r; + uint8_t body[100]; + + /* Simple message: Data, fits easily in cell. */ + msg1 = tor_malloc_zero(sizeof(relay_msg_t)); + msg1->command = RELAY_COMMAND_DATA; + msg1->stream_id = 0x250; + msg1->length = 11; + msg1->body = body; + strlcpy((char*)body, "hello world", sizeof(body)); + + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V0, msg1, &cell); + tt_int_op(r, OP_EQ, 0); + tt_int_op(cell.command, OP_EQ, CELL_RELAY); + tt_int_op(cell.circ_id, OP_EQ, 0); + // command, recognized, streamid, digest, len, payload, zero-padding. + test_memeq_hex(cell.payload, + "02" "0000" "0250" "00000000" "000B" + "68656c6c6f20776f726c64" "00000000"); + // random padding + size_t used = RELAY_HEADER_SIZE_V0 + 11 + 4; + tt_assert(!fast_mem_is_zero((char*)cell.payload + used, + CELL_PAYLOAD_SIZE - used)); + + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, 0); + tt_int_op(cell.command, OP_EQ, CELL_RELAY); + tt_int_op(cell.circ_id, OP_EQ, 0); + // tag, command, len, optional streamid, payload, zero-padding + test_memeq_hex(cell.payload, + "00000000000000000000000000000000" + "02" "000B" "0250" + "68656c6c6f20776f726c64" "00000000"); + // random padding. + used = RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + 11 + 4; + tt_assert(!fast_mem_is_zero((char*)cell.payload + used, + CELL_PAYLOAD_SIZE - used)); + + /* Message without stream ID: SENDME, fits easily in cell. */ + relay_msg_clear(msg1); + msg1->command = RELAY_COMMAND_SENDME; + msg1->stream_id = 0; + msg1->length = 20; + msg1->body = body; + strlcpy((char *)body, "hello i am a tag....", sizeof(body)); + + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V0, msg1, &cell); + tt_int_op(r, OP_EQ, 0); + tt_int_op(cell.command, OP_EQ, CELL_RELAY); + tt_int_op(cell.circ_id, OP_EQ, 0); + // command, recognized, streamid, digest, len, payload, zero-padding. + test_memeq_hex(cell.payload, + "05" "0000" "0000" "00000000" "0014" + "68656c6c6f206920616d2061207461672e2e2e2e" "00000000"); + // random padding + used = RELAY_HEADER_SIZE_V0 + 20 + 4; + tt_assert(!fast_mem_is_zero((char*)cell.payload + used, + CELL_PAYLOAD_SIZE - used)); + + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, 0); + tt_int_op(cell.command, OP_EQ, CELL_RELAY); + tt_int_op(cell.circ_id, OP_EQ, 0); + // tag, command, len, optional streamid, payload, zero-padding + test_memeq_hex(cell.payload, + "00000000000000000000000000000000" + "05" "0014" + "68656c6c6f206920616d2061207461672e2e2e2e" "00000000"); + // random padding. + used = RELAY_HEADER_SIZE_V1_NO_STREAM_ID + 20 + 4; + tt_assert(!fast_mem_is_zero((char*)cell.payload + used, + CELL_PAYLOAD_SIZE - used)); + + done: + relay_msg_free(msg1); + tor_free(mem_op_hex_tmp); +} + +/** Helper for test_cfmt_relay_cell_padding. + * Requires that that the body of 'msg' ends with 'pre_padding_byte', + * and that when encoded, the zero-padding (if any) will appear at + * offset 'zeros_begin_at' in the message. + */ +static void +msg_encoder_padding_test(const relay_msg_t *msg, + relay_cell_fmt_t fmt, + uint8_t pre_padding_byte, + size_t zeros_begin_at) +{ + cell_t cell; + int n = 16, i; + /* We set this to 0 as soon as we find that the first byte of + * random padding has been set. */ + bool padded_first = false; + /* We set this to true as soon as we find that the last byte of + * random padding has been set */ + bool padded_last = false; + + tt_int_op(zeros_begin_at, OP_LE, CELL_PAYLOAD_SIZE); + + size_t expect_n_zeros = MIN(4, CELL_PAYLOAD_SIZE - zeros_begin_at); + ssize_t first_random_at = -1; + if (CELL_PAYLOAD_SIZE - zeros_begin_at > 4) { + first_random_at = CELL_PAYLOAD_SIZE - zeros_begin_at + 4; + } + + for (i = 0; i < n; ++i) { + memset(&cell, 0, sizeof(cell)); + tt_int_op(0, OP_EQ, + relay_msg_encode_cell(fmt, msg, &cell)); + + const uint8_t *body = cell.payload; + tt_int_op(body[zeros_begin_at - 1], OP_EQ, pre_padding_byte); + + if (expect_n_zeros) { + tt_assert(fast_mem_is_zero((char*)body + zeros_begin_at, + expect_n_zeros)); + } + if (first_random_at >= 0) { + if (body[first_random_at]) + padded_first = true; + if (body[CELL_PAYLOAD_SIZE-1]) + padded_last = true; + } + } + + if (first_random_at >= 0) { + tt_assert(padded_first); + tt_assert(padded_last); + } + + done: + ; +} + +static void +test_cfmt_relay_cell_padding(void *arg) +{ + (void)arg; + relay_msg_t *msg1 = NULL; + uint8_t buf[500]; // Longer than it needs to be. + memset(buf, 0xff, sizeof(buf)); + + /* Simple message; we'll adjust the length and encode it. */ + msg1 = tor_malloc_zero(sizeof(relay_msg_t)); + msg1->command = RELAY_COMMAND_DATA; + msg1->stream_id = 0x250; + msg1->body = buf; + + // Empty message + msg1->length = 0; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V0, 0x00, + RELAY_HEADER_SIZE_V0); + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0x50, + RELAY_HEADER_SIZE_V1_WITH_STREAM_ID); + + // Short message + msg1->length = 10; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V0, 0xff, + RELAY_HEADER_SIZE_V0 + 10); + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + 10); + + // Message where zeros extend exactly up to the end of the cell. + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0 - 4; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V0, 0xff, + RELAY_HEADER_SIZE_V0 + msg1->length); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID - 4; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + msg1->length); + + // Message where zeros would intersect with the end of the cell. + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0 - 3; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V0, 0xff, + RELAY_HEADER_SIZE_V0 + msg1->length); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID - 3; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + msg1->length); + + // Message with no room for zeros + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V0, 0xff, + RELAY_HEADER_SIZE_V0 + msg1->length); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + msg1->length); + + /////////////// + // V1 cases with no stream ID. + msg1->stream_id = 0; + msg1->command = RELAY_COMMAND_EXTENDED; + + msg1->length = 0; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0x00, + RELAY_HEADER_SIZE_V1_NO_STREAM_ID); + msg1->length = 10; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_NO_STREAM_ID + 10); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_NO_STREAM_ID - 4; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_NO_STREAM_ID + msg1->length); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_NO_STREAM_ID - 3; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_NO_STREAM_ID + msg1->length); + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_NO_STREAM_ID; + msg_encoder_padding_test(msg1, RELAY_CELL_FORMAT_V1, 0xff, + RELAY_HEADER_SIZE_V1_NO_STREAM_ID + msg1->length); + + relay_msg_free(msg1); +} + +static void +test_cfmt_relay_msg_encoding_error(void *arg) +{ + (void)arg; +#ifdef ALL_BUGS_ARE_FATAL + // This test triggers many nonfatal assertions. + tt_skip(); + done: + ; +#else + relay_msg_t *msg1 = NULL; + int r; + cell_t cell; + uint8_t buf[500]; // Longer than it needs to be. + memset(buf, 0xff, sizeof(buf)); + + msg1 = tor_malloc_zero(sizeof(relay_msg_t)); + msg1->command = RELAY_COMMAND_DATA; + msg1->stream_id = 0x250; + msg1->body = buf; + + tor_capture_bugs_(5); + // Too long for v0. + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0 + 1; + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V0, msg1, &cell); + tt_int_op(r, OP_EQ, -1); + + // Too long for v1, with stream ID. + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_WITH_STREAM_ID + 1; + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, -1); + + // Too long for v1 with no stream ID. + msg1->command = RELAY_COMMAND_EXTENDED; + msg1->stream_id = 0; + msg1->length = CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V1_NO_STREAM_ID + 1; + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, -1); + + // Invalid (present) stream ID for V1. + msg1->stream_id = 10; + msg1->length = 20; + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, -1); + + // Invalid (absent) stream ID for V1. + msg1->stream_id = 0; + msg1->command = RELAY_COMMAND_DATA; + r = relay_msg_encode_cell(RELAY_CELL_FORMAT_V1, msg1, &cell); + tt_int_op(r, OP_EQ, -1); + + done: + tor_end_capture_bugs_(); + relay_msg_free(msg1); +#endif +} + +static void +test_cfmt_relay_msg_decoding_simple(void *arg) +{ + (void) arg; + cell_t cell; + relay_msg_t *msg1 = NULL; + const char *s; + + memset(&cell, 0, sizeof(cell)); + cell.command = CELL_RELAY; + + // V0 decoding, short message. + s = "02" "0000" "0250" "00000000" "000B" + "68656c6c6f20776f726c64" "00000000"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V0, &cell); + tt_assert(msg1); + + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_DATA); + tt_int_op(msg1->stream_id, OP_EQ, 0x250); + tt_int_op(msg1->length, OP_EQ, 11); + tt_mem_op(msg1->body, OP_EQ, "hello world", 11); + relay_msg_free(msg1); + + // V0 decoding, message up to length of cell. + memset(cell.payload, 0, sizeof(cell.payload)); + s = "02" "0000" "0250" "00000000" "01F2"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V0, &cell); + tt_assert(msg1); + + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_DATA); + tt_int_op(msg1->stream_id, OP_EQ, 0x250); + tt_int_op(msg1->length, OP_EQ, 498); + tt_assert(fast_mem_is_zero((char*)msg1->body, 498)); + relay_msg_free(msg1); + + // V1 decoding, short message, no stream ID. + s = "00000000000000000000000000000000" + "05" "0014" + "68656c6c6f206920616d2061207461672e2e2e2e" "00000000"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_assert(msg1); + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_SENDME); + tt_int_op(msg1->stream_id, OP_EQ, 0); + tt_int_op(msg1->length, OP_EQ, 20); + tt_mem_op(msg1->body, OP_EQ, "hello i am a tag....", 20); + relay_msg_free(msg1); + + // V1 decoding, up to length of cell, no stream ID. + memset(cell.payload, 0, sizeof(cell.payload)); + s = "00000000000000000000000000000000" + "05" "01EA"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_assert(msg1); + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_SENDME); + tt_int_op(msg1->stream_id, OP_EQ, 0); + tt_int_op(msg1->length, OP_EQ, 490); + tt_assert(fast_mem_is_zero((char*)msg1->body, 490)); + relay_msg_free(msg1); + + // V1 decoding, short message, with stream ID. + s = "00000000000000000000000000000000" + "02" "000B" "0250" + "68656c6c6f20776f726c64" "00000000"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_assert(msg1); + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_DATA); + tt_int_op(msg1->stream_id, OP_EQ, 0x250); + tt_int_op(msg1->length, OP_EQ, 11); + tt_mem_op(msg1->body, OP_EQ, "hello world", 11); + relay_msg_free(msg1); + + // V1 decoding, up to length of cell, with stream ID. + memset(cell.payload, 0, sizeof(cell.payload)); + s = "00000000000000000000000000000000" + "02" "01E8" "0250"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_assert(msg1); + tt_int_op(msg1->command, OP_EQ, RELAY_COMMAND_DATA); + tt_int_op(msg1->stream_id, OP_EQ, 0x250); + tt_int_op(msg1->length, OP_EQ, 488); + tt_assert(fast_mem_is_zero((char*)msg1->body, 488)); + relay_msg_free(msg1); + + done: + relay_msg_free(msg1); +} + +static void +test_cfmt_relay_msg_decoding_error(void *arg) +{ + (void) arg; + relay_msg_t *msg1 = NULL; + cell_t cell; + const char *s; + memset(&cell, 0, sizeof(cell)); + + // V0, too long. + cell.command = CELL_RELAY; + s = "02" "0000" "0250" "00000000" "01F3"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V0, &cell); + tt_ptr_op(msg1, OP_EQ, NULL); + + // V1, command unrecognized. + s = "00000000000000000000000000000000" + "F0" "000C" "0250"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_ptr_op(msg1, OP_EQ, NULL); + + // V1, too long (with stream ID) + s = "00000000000000000000000000000000" + "02" "01E9" "0250"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_ptr_op(msg1, OP_EQ, NULL); + + // V1, too long (without stream ID) + s = "00000000000000000000000000000000" + "05" "01EB"; + base16_decode((char*)cell.payload, sizeof(cell.payload), s, strlen(s)); + msg1 = relay_msg_decode_cell(RELAY_CELL_FORMAT_V1, &cell); + tt_ptr_op(msg1, OP_EQ, NULL); + + done: + relay_msg_free(msg1); +} + #define TEST(name, flags) \ { #name, test_cfmt_ ## name, flags, 0, NULL } @@ -1213,5 +1607,10 @@ struct testcase_t cell_format_tests[] = { TEST(extended_cells, 0), TEST(resolved_cells, 0), TEST(is_destroy, 0), + TEST(relay_msg_encoding_simple, 0), + TEST(relay_cell_padding, 0), + TEST(relay_msg_encoding_error, 0), + TEST(relay_msg_decoding_simple, 0), + TEST(relay_msg_decoding_error, 0), END_OF_TESTCASES }; diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c @@ -21,6 +21,7 @@ #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "core/or/onion.h" +#include "core/or/relay_msg.h" #include "core/or/cell_st.h" #include "core/or/cpath_build_state_st.h" @@ -1278,7 +1279,7 @@ static void test_circuit_extend(void *arg) { (void)arg; - cell_t *cell = tor_malloc_zero(sizeof(cell_t)); + relay_msg_t *msg = tor_malloc_zero(sizeof(relay_msg_t)); channel_t *p_chan = tor_malloc_zero(sizeof(channel_t)); or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t)); circuit_t *circ = TO_CIRCUIT(or_circ); @@ -1293,10 +1294,14 @@ test_circuit_extend(void *arg) setup_full_capture_of_logs(LOG_INFO); + msg->command = RELAY_COMMAND_EXTEND2; + uint8_t body[3] = "xyz"; + msg->body = body; + #ifndef ALL_BUGS_ARE_FATAL /* Circuit must be non-NULL */ tor_capture_bugs_(1); - tt_int_op(circuit_extend(cell, NULL), OP_EQ, -1); + tt_int_op(circuit_extend(msg, NULL), OP_EQ, -1); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, "!(ASSERT_PREDICT_UNLIKELY_(!circ))"); @@ -1308,7 +1313,7 @@ test_circuit_extend(void *arg) tt_int_op(circuit_extend(NULL, circ), OP_EQ, -1); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, - "!(ASSERT_PREDICT_UNLIKELY_(!cell))"); + "!(ASSERT_PREDICT_UNLIKELY_(!rmsg))"); tor_end_capture_bugs_(); mock_clean_saved_logs(); @@ -1324,13 +1329,13 @@ test_circuit_extend(void *arg) /* Clients can't extend */ server = 0; - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); expect_log_msg("Got an extend cell, but running as a client. Closing.\n"); mock_clean_saved_logs(); /* But servers can. Unpack the cell, but fail parsing. */ server = 1; - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); expect_log_msg("Can't parse extend cell. Closing circuit.\n"); mock_clean_saved_logs(); @@ -1343,7 +1348,7 @@ test_circuit_extend(void *arg) mock_extend_cell_parse_result = 0; mock_extend_cell_parse_calls = 0; - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); expect_log_msg( "Client asked me to extend without specifying an id_digest.\n"); @@ -1354,7 +1359,7 @@ test_circuit_extend(void *arg) memset(&mock_extend_cell_parse_cell_out.node_id, 0xAA, sizeof(mock_extend_cell_parse_cell_out.node_id)); - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); expect_log_msg("Client asked me to extend to a zero destination port " "or unspecified address '[scrubbed]'.\n"); @@ -1368,7 +1373,7 @@ test_circuit_extend(void *arg) #ifndef ALL_BUGS_ARE_FATAL tor_capture_bugs_(1); - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1); tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ, @@ -1389,7 +1394,7 @@ test_circuit_extend(void *arg) /* Test circuit not established, but don't launch another one */ mock_channel_get_for_extend_launch_out = 0; mock_channel_get_for_extend_nchan = NULL; - tt_int_op(circuit_extend(cell, circ), OP_EQ, 0); + tt_int_op(circuit_extend(msg, circ), OP_EQ, 0); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); @@ -1409,7 +1414,7 @@ test_circuit_extend(void *arg) mock_channel_get_for_extend_launch_out = 1; mock_channel_get_for_extend_nchan = NULL; mock_channel_connect_nchan = fake_n_chan; - tt_int_op(circuit_extend(cell, circ), OP_EQ, 0); + tt_int_op(circuit_extend(msg, circ), OP_EQ, 0); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); tt_int_op(mock_channel_connect_calls, OP_EQ, 1); @@ -1433,7 +1438,7 @@ test_circuit_extend(void *arg) mock_channel_get_for_extend_nchan = fake_n_chan; mock_channel_connect_nchan = NULL; mock_circuit_deliver_create_cell_result = 0; - tt_int_op(circuit_extend(cell, circ), OP_EQ, 0); + tt_int_op(circuit_extend(msg, circ), OP_EQ, 0); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); tt_int_op(mock_channel_connect_calls, OP_EQ, 0); @@ -1456,7 +1461,7 @@ test_circuit_extend(void *arg) mock_channel_get_for_extend_nchan = fake_n_chan; mock_channel_connect_nchan = NULL; mock_circuit_deliver_create_cell_result = -1; - tt_int_op(circuit_extend(cell, circ), OP_EQ, -1); + tt_int_op(circuit_extend(msg, circ), OP_EQ, -1); tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1); tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1); tt_int_op(mock_channel_connect_calls, OP_EQ, 0); @@ -1502,7 +1507,7 @@ test_circuit_extend(void *arg) mock_circuit_deliver_create_cell_calls = 0; mock_circuit_deliver_create_cell_result = 0; - tor_free(cell); + relay_msg_free(msg); /* circ and or_circ are the same object */ tor_free(circ->n_hop); tor_free(circ->n_chan_create_cell); diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c @@ -24,6 +24,7 @@ #include "core/or/circuitpadding.h" #include "core/or/circuitpadding_machines.h" #include "core/or/extendinfo.h" +#include "core/or/relay_msg.h" #include "core/mainloop/netstatus.h" #include "core/crypto/relay_crypto.h" #include "core/or/protover.h" @@ -172,11 +173,16 @@ circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ, const char *filename, int lineno) { (void)cell; (void)on_stream; (void)filename; (void)lineno; + relay_msg_t *msg = NULL; + + msg = relay_msg_decode_cell(RELAY_CELL_FORMAT_V0, cell); + if (! msg) + goto done; if (circ == client_side) { if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATE) { // Deliver to relay - circpad_handle_padding_negotiate(relay_side, cell); + circpad_handle_padding_negotiate(relay_side, msg); } else { int is_target_hop = circpad_padding_is_from_expected_hop(circ, @@ -190,7 +196,7 @@ circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ, // Receive padding cell at middle circpad_deliver_recognized_relay_cell_events(relay_side, - cell->payload[0], NULL); + msg->command, NULL); } n_client_cells++; } else if (circ == relay_side) { @@ -199,11 +205,11 @@ circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ, if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATED) { // XXX: blah need right layer_hint.. if (deliver_negotiated) - circpad_handle_padding_negotiated(client_side, cell, + circpad_handle_padding_negotiated(client_side, msg, TO_ORIGIN_CIRCUIT(client_side) ->cpath->next); } else if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATE) { - circpad_handle_padding_negotiate(client_side, cell); + circpad_handle_padding_negotiate(client_side, msg); } else { // No need to pretend a padding cell was sent: This event is // now emitted internally when the circuitpadding code sends them. @@ -211,7 +217,7 @@ circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ, // Receive padding cell at client circpad_deliver_recognized_relay_cell_events(client_side, - cell->payload[0], + msg->command, TO_ORIGIN_CIRCUIT(client_side)->cpath->next); } @@ -219,6 +225,7 @@ circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ, } done: + relay_msg_free(msg); timers_advance_and_run(1); return 0; } @@ -1251,7 +1258,7 @@ test_circuitpadding_wronghop(void *arg) */ (void)arg; uint32_t read_bw = 0, overhead_bw = 0; - cell_t cell; + relay_msg_t msg; signed_error_t ret; origin_circuit_t *orig_client; int64_t actual_mocked_monotime_start; @@ -1331,17 +1338,21 @@ test_circuitpadding_wronghop(void *arg) orig_client->n_overhead_read_circ_bw); /* 2. Test padding negotiated not handled from hops 1,3 */ - ret = circpad_handle_padding_negotiated(client_side, &cell, + memset(&msg, 0, sizeof(msg)); + ret = circpad_handle_padding_negotiated(client_side, &msg, TO_ORIGIN_CIRCUIT(client_side)->cpath); tt_int_op(ret, OP_EQ, -1); - ret = circpad_handle_padding_negotiated(client_side, &cell, + ret = circpad_handle_padding_negotiated(client_side, &msg, TO_ORIGIN_CIRCUIT(client_side)->cpath->next->next); tt_int_op(ret, OP_EQ, -1); /* 3. Garbled negotiated cell */ - memset(&cell, 255, sizeof(cell)); - ret = circpad_handle_padding_negotiated(client_side, &cell, + memset(&msg, 0, sizeof(msg)); + uint8_t buf[99]; + memset(buf, 0xff, 99); + msg.body = buf; + ret = circpad_handle_padding_negotiated(client_side, &msg, TO_ORIGIN_CIRCUIT(client_side)->cpath->next); tt_int_op(ret, OP_EQ, -1); @@ -1350,7 +1361,7 @@ test_circuitpadding_wronghop(void *arg) overhead_bw = orig_client->n_overhead_read_circ_bw; relay_send_command_from_edge(0, relay_side, RELAY_COMMAND_PADDING_NEGOTIATE, - (void*)cell.payload, + "xyz", (size_t)3, NULL); tt_int_op(read_bw, OP_EQ, orig_client->n_delivered_read_circ_bw); @@ -1371,12 +1382,12 @@ test_circuitpadding_wronghop(void *arg) tt_int_op(n_client_cells, OP_EQ, 2); /* 6. Sending negotiated command to relay does nothing */ - ret = circpad_handle_padding_negotiated(relay_side, &cell, NULL); + ret = circpad_handle_padding_negotiated(relay_side, &msg, NULL); tt_int_op(ret, OP_EQ, -1); /* 7. Test garbled negotiated cell (bad command 255) */ - memset(&cell, 0, sizeof(cell)); - ret = circpad_handle_padding_negotiate(relay_side, &cell); + relay_msg_clear(&msg); + ret = circpad_handle_padding_negotiate(relay_side, &msg); tt_int_op(ret, OP_EQ, -1); tt_int_op(n_client_cells, OP_EQ, 2); @@ -1434,6 +1445,7 @@ test_circuitpadding_wronghop(void *arg) UNMOCK(circuitmux_attach_circuit); nodes_free(); testing_disable_reproducible_rng(); + relay_msg_clear(&msg); } void @@ -3100,17 +3112,18 @@ static void test_circuitpadding_ignore_non_padding_cells(void *arg) { int retval; - relay_header_t rh; (void) arg; client_side = (circuit_t *)origin_circuit_new(); client_side->purpose = CIRCUIT_PURPOSE_C_CIRCUIT_PADDING; - rh.command = RELAY_COMMAND_BEGIN; + relay_msg_t msg; + memset(&msg, 0, sizeof(msg)); + msg.command = RELAY_COMMAND_BEGIN; setup_full_capture_of_logs(LOG_INFO); - retval = handle_relay_cell_command(NULL, client_side, NULL, NULL, &rh, 0); + retval = handle_relay_msg(&msg, client_side, NULL, NULL, 0); tt_int_op(retval, OP_EQ, 0); expect_log_msg_containing("Ignored cell"); diff --git a/src/test/test_conflux_cell.c b/src/test/test_conflux_cell.c @@ -13,15 +13,19 @@ #include "core/or/conflux_cell.h" #include "core/or/conflux_st.h" #include "trunnel/conflux.h" +#include "core/or/relay_msg.h" +#include "core/or/relay_msg_st.h" #include "lib/crypt_ops/crypto_rand.h" static void test_link(void *arg) { - cell_t cell; conflux_cell_link_t link; conflux_cell_link_t *decoded_link = NULL; + relay_msg_t msg; + uint8_t buf0[RELAY_PAYLOAD_SIZE_MAX]; + uint8_t buf1[RELAY_PAYLOAD_SIZE_MAX]; (void) arg; @@ -34,14 +38,15 @@ test_link(void *arg) crypto_rand((char *) link.nonce, sizeof(link.nonce)); - ssize_t cell_len = build_link_cell(&link, cell.payload+RELAY_HEADER_SIZE); + ssize_t cell_len = build_link_cell(&link, buf0); tt_int_op(cell_len, OP_GT, 0); + msg.length = cell_len; + msg.body = buf0; - decoded_link = conflux_cell_parse_link(&cell, cell_len); + decoded_link = conflux_cell_parse_link(&msg); tt_assert(decoded_link); - uint8_t buf[RELAY_PAYLOAD_SIZE]; - ssize_t enc_cell_len = build_link_cell(decoded_link, buf); + ssize_t enc_cell_len = build_link_cell(decoded_link, buf1); tt_int_op(cell_len, OP_EQ, enc_cell_len); /* Validate the original link object with the decoded one. */ @@ -49,6 +54,7 @@ test_link(void *arg) tor_free(decoded_link); done: + relay_msg_clear(&msg); tor_free(decoded_link); } @@ -57,4 +63,3 @@ struct testcase_t conflux_cell_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_conflux_pool.c b/src/test/test_conflux_pool.c @@ -29,6 +29,7 @@ #include "core/or/congestion_control_st.h" #include "core/or/congestion_control_common.h" #include "core/or/extendinfo.h" +#include "core/or/relay_msg.h" #include "core/mainloop/netstatus.h" #include "core/crypto/relay_crypto.h" #include "core/or/protover.h" @@ -223,6 +224,7 @@ static void process_mock_cell_delivery(void) { relay_header_t rh; + relay_msg_t *msg = NULL; cell_delivery_t *delivery = smartlist_pop_last(mock_cell_delivery); tor_assert(delivery); @@ -232,16 +234,20 @@ process_mock_cell_delivery(void) timers_advance_and_run(1); - switch (cell->payload[0]) { + msg = relay_msg_decode_cell(RELAY_CELL_FORMAT_V0, cell); + + tor_assert(msg); + + switch (msg->command) { case RELAY_COMMAND_CONFLUX_LINK: tor_assert(!CIRCUIT_IS_ORIGIN(dest_circ)); - conflux_process_link(dest_circ, cell, rh.length); + conflux_process_link(dest_circ, msg); break; case RELAY_COMMAND_CONFLUX_LINKED: tor_assert(CIRCUIT_IS_ORIGIN(dest_circ)); conflux_process_linked(dest_circ, TO_ORIGIN_CIRCUIT(dest_circ)->cpath->prev, - cell, rh.length); + msg); break; case RELAY_COMMAND_CONFLUX_LINKED_ACK: tor_assert(!CIRCUIT_IS_ORIGIN(dest_circ)); @@ -253,12 +259,13 @@ process_mock_cell_delivery(void) // the case where the switch is initiated by the exit, we will need to // get the cpath layer hint for the client. tor_assert(!CIRCUIT_IS_ORIGIN(dest_circ)); - conflux_process_switch_command(dest_circ, NULL, cell, &rh); + conflux_process_switch_command(dest_circ, NULL, msg); break; } tor_free(delivery); tor_free(cell); + relay_msg_free(msg); return; } diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c @@ -19,6 +19,7 @@ #include "core/or/connection_edge.h" #include "core/or/sendme.h" #include "core/or/relay.h" +#include "core/or/relay_msg.h" #include "test/test.h" #include "test/log_test_helpers.h" @@ -172,19 +173,20 @@ fake_entry_conn(origin_circuit_t *oncirc, streamid_t id) return entryconn; } -#define PACK_CELL(id, cmd, body_s) do { \ - memset(&cell, 0, sizeof(cell)); \ - memset(&rh, 0, sizeof(rh)); \ - memcpy(cell.payload+RELAY_HEADER_SIZE, (body_s), sizeof((body_s))-1); \ - rh.length = sizeof((body_s))-1; \ - rh.command = (cmd); \ - rh.stream_id = (id); \ - relay_header_pack((uint8_t*)&cell.payload, &rh); \ +#define PACK_CELL(id, cmd, body_s) do { \ + len_tmp = sizeof(body_s)-1; \ + relay_msg_free(msg); \ + msg = tor_malloc_zero(sizeof(relay_msg_t)); \ + msg->command = (cmd); \ + msg->stream_id = (id); \ + msg->body = cell_buf; \ + msg->length = len_tmp; \ + memcpy(cell_buf, (body_s), len_tmp); \ } while (0) #define ASSERT_COUNTED_BW() do { \ - tt_int_op(circ->n_delivered_read_circ_bw, OP_EQ, delivered+rh.length); \ + tt_int_op(circ->n_delivered_read_circ_bw, OP_EQ, delivered+msg->length); \ tt_int_op(circ->n_overhead_read_circ_bw, OP_EQ, \ - overhead+RELAY_PAYLOAD_SIZE-rh.length); \ + overhead+RELAY_PAYLOAD_SIZE-msg->length); \ delivered = circ->n_delivered_read_circ_bw; \ overhead = circ->n_overhead_read_circ_bw; \ } while (0) @@ -196,14 +198,15 @@ fake_entry_conn(origin_circuit_t *oncirc, streamid_t id) static int subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) { - cell_t cell; - relay_header_t rh; + relay_msg_t *msg = NULL; + size_t len_tmp; edge_connection_t *edgeconn; entry_connection_t *entryconn2=NULL; entry_connection_t *entryconn3=NULL; entry_connection_t *entryconn4=NULL; int delivered = circ->n_delivered_read_circ_bw; int overhead = circ->n_overhead_read_circ_bw; + uint8_t cell_buf[RELAY_PAYLOAD_SIZE_MAX]; /* Make new entryconns */ entryconn2 = fake_entry_conn(circ, init_id); @@ -225,36 +228,36 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) /* Data cell not in the half-opened list */ PACK_CELL(4000, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme cell not in the half-opened list */ PACK_CELL(4000, RELAY_COMMAND_SENDME, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Connected cell not in the half-opened list */ PACK_CELL(4000, RELAY_COMMAND_CONNECTED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Resolved cell not in the half-opened list */ PACK_CELL(4000, RELAY_COMMAND_RESOLVED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -262,9 +265,9 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) edgeconn = ENTRY_TO_EDGE_CONN(entryconn2); PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -273,9 +276,9 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); data_cells--; @@ -283,9 +286,9 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -294,9 +297,9 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); sendme_cells--; @@ -304,9 +307,9 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -314,18 +317,18 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -335,7 +338,7 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) /* sendme cell on open entryconn with full window */ PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); int ret = - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); tt_int_op(ret, OP_EQ, -END_CIRC_REASON_TORPROTOCOL); ASSERT_UNCOUNTED_BW(); @@ -346,18 +349,18 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) connection_edge_reached_eof(edgeconn); PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -365,16 +368,16 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); ret = - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); tt_int_op(ret, OP_NE, -END_CIRC_REASON_TORPROTOCOL); ASSERT_UNCOUNTED_BW(); @@ -382,9 +385,9 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -400,16 +403,16 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED, "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED, "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -417,9 +420,9 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -427,17 +430,19 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) - pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); else - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); + relay_msg_free(msg); connection_free_minimal(ENTRY_TO_CONN(entryconn2)); connection_free_minimal(ENTRY_TO_CONN(entryconn3)); connection_free_minimal(ENTRY_TO_CONN(entryconn4)); return 1; done: + relay_msg_free(msg); connection_free_minimal(ENTRY_TO_CONN(entryconn2)); connection_free_minimal(ENTRY_TO_CONN(entryconn3)); connection_free_minimal(ENTRY_TO_CONN(entryconn4)); @@ -666,14 +671,15 @@ test_halfstream_wrap(void *arg) static void test_circbw_relay(void *arg) { - cell_t cell; - relay_header_t rh; + relay_msg_t *msg = NULL; + size_t len_tmp; tor_addr_t addr; edge_connection_t *edgeconn; entry_connection_t *entryconn1=NULL; origin_circuit_t *circ; int delivered = 0; int overhead = 0; + uint8_t cell_buf[RELAY_PAYLOAD_SIZE_MAX]; (void)arg; @@ -692,23 +698,22 @@ test_circbw_relay(void *arg) /* Stream id 0: Not counted */ PACK_CELL(0, RELAY_COMMAND_END, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, 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, + msg->length = connected_cell_format_payload(cell_buf, + &addr, 1024); + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); @@ -718,7 +723,7 @@ test_circbw_relay(void *arg) 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, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); @@ -727,65 +732,65 @@ test_circbw_relay(void *arg) /* Connected cell after open: not counted */ PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on valid stream: counted */ edgeconn->package_window -= STREAMWINDOW_INCREMENT; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Sendme on valid stream with full window: not counted */ PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); edgeconn->package_window = STREAMWINDOW_START; - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on unknown stream: not counted */ PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -796,44 +801,44 @@ test_circbw_relay(void *arg) circ->cpath->package_window = 901; sendme_record_cell_digest_on_circ(TO_CIRCUIT(circ), circ->cpath); circ->cpath->package_window = 900; - connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, 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, + connection_edge_process_relay_cell(msg, TO_CIRCUIT(circ), NULL, circ->cpath); ASSERT_UNCOUNTED_BW(); @@ -848,10 +853,11 @@ test_circbw_relay(void *arg) /* 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); + pathbias_count_valid_cells(TO_CIRCUIT(circ), msg); tt_int_op(circ->base_.marked_for_close, OP_EQ, 1); done: + relay_msg_free(msg); UNMOCK(connection_start_reading); UNMOCK(connection_mark_unattached_ap_); UNMOCK(connection_mark_for_close_internal_); @@ -872,17 +878,19 @@ test_relaycell_resolved(void *arg) { entry_connection_t *entryconn; edge_connection_t *edgeconn; - cell_t cell; - relay_header_t rh; + relay_msg_t *msg = NULL; int r; or_options_t *options = get_options_mutable(); + size_t len_tmp; + uint8_t cell_buf[RELAY_PAYLOAD_SIZE_MAX]; #define SET_CELL(s) do { \ - memset(&cell, 0, sizeof(cell)); \ - memset(&rh, 0, sizeof(rh)); \ - memcpy(cell.payload + RELAY_HEADER_SIZE, (s), sizeof((s))-1); \ - rh.length = sizeof((s))-1; \ - rh.command = RELAY_COMMAND_RESOLVED; \ + relay_msg_free(msg); \ + msg = tor_malloc_zero(sizeof(relay_msg_t)); \ + len_tmp = sizeof(s) - 1; \ + msg->body = cell_buf; \ + msg->length = len_tmp; \ + memcpy(cell_buf, s, len_tmp); \ } while (0) #define MOCK_RESET() do { \ srm_ncalls = mum_ncalls = 0; \ @@ -892,20 +900,20 @@ test_relaycell_resolved(void *arg) tt_ptr_op(mum_conn, OP_EQ, entryconn); \ tt_int_op(mum_endreason, OP_EQ, (reason)); \ } while (0) -#define ASSERT_RESOLVED_CALLED(atype, answer, ttl, expires) do { \ - tt_int_op(srm_ncalls, OP_EQ, 1); \ - tt_ptr_op(srm_conn, OP_EQ, entryconn); \ - tt_int_op(srm_atype, OP_EQ, (atype)); \ - if ((answer) != NULL) { \ - tt_int_op(srm_alen, OP_EQ, sizeof(answer)-1); \ - tt_int_op(srm_alen, OP_LT, 512); \ - tt_int_op(srm_answer_is_set, OP_EQ, 1); \ - tt_mem_op(srm_answer, OP_EQ, answer, sizeof(answer)-1); \ - } else { \ - tt_int_op(srm_answer_is_set, OP_EQ, 0); \ - } \ - tt_int_op(srm_ttl, OP_EQ, ttl); \ - tt_i64_op(srm_expires, OP_EQ, expires); \ +#define ASSERT_RESOLVED_CALLED(atype, answer, ttl, expires) do { \ + tt_int_op(srm_ncalls, OP_EQ, 1); \ + tt_ptr_op(srm_conn, OP_EQ, entryconn); \ + tt_int_op(srm_atype, OP_EQ, (atype)); \ + if ((answer) != NULL) { \ + tt_int_op(srm_alen, OP_EQ, sizeof(answer)-1); \ + tt_int_op(srm_alen, OP_LT, 512); \ + tt_int_op(srm_answer_is_set, OP_EQ, 1); \ + tt_mem_op(srm_answer, OP_EQ, answer, sizeof(answer)-1); \ + } else { \ + tt_int_op(srm_answer_is_set, OP_EQ, 0); \ + } \ + tt_int_op(srm_ttl, OP_EQ, ttl); \ + tt_i64_op(srm_expires, OP_EQ, expires); \ } while (0) (void)arg; @@ -930,7 +938,7 @@ test_relaycell_resolved(void *arg) /* Try with connection in non-RESOLVE_WAIT state: cell gets ignored */ MOCK_RESET(); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); tt_int_op(srm_ncalls, OP_EQ, 0); tt_int_op(mum_ncalls, OP_EQ, 0); @@ -944,7 +952,7 @@ test_relaycell_resolved(void *arg) /* We prefer ipv4, so we should get the first ipv4 answer */ MOCK_RESET(); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -953,7 +961,7 @@ test_relaycell_resolved(void *arg) /* But we may be discarding private answers. */ MOCK_RESET(); options->ClientDNSRejectInternalAddresses = 1; - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -962,7 +970,7 @@ test_relaycell_resolved(void *arg) /* now prefer ipv6, and get the first ipv6 answer */ entryconn->entry_cfg.prefer_ipv6 = 1; MOCK_RESET(); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -974,7 +982,7 @@ test_relaycell_resolved(void *arg) /* With a cell that only has IPv4, we report IPv4 even if we prefer IPv6 */ MOCK_RESET(); SET_CELL("\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -984,7 +992,7 @@ test_relaycell_resolved(void *arg) * ipv4 */ MOCK_RESET(); entryconn->entry_cfg.ipv4_traffic = 0; - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -994,7 +1002,7 @@ test_relaycell_resolved(void *arg) MOCK_RESET(); entryconn->entry_cfg.ipv4_traffic = 1; entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -1003,7 +1011,7 @@ test_relaycell_resolved(void *arg) /* A hostname cell is fine though. */ MOCK_RESET(); SET_CELL("\x00\x0fwww.example.com\x00\x01\x00\x00"); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); @@ -1013,7 +1021,7 @@ test_relaycell_resolved(void *arg) MOCK_RESET(); entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE; SET_CELL("\x04\x04\x01\x02\x03\x04"); /* no ttl */ - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL); tt_int_op(srm_ncalls, OP_EQ, 0); @@ -1024,7 +1032,7 @@ test_relaycell_resolved(void *arg) "\x04\x04\x7f\x00\x01\x02\x00\x00\x01\x00" /* IPv4: 192.168.1.1, ttl 256 */ "\x04\x04\xc0\xa8\x01\x01\x00\x00\x01\x00"); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL); ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, 0, TIME_MAX); @@ -1032,13 +1040,14 @@ test_relaycell_resolved(void *arg) /* Legit error code */ MOCK_RESET(); SET_CELL("\xf0\x15" "quiet and meaningless" "\x00\x00\x0f\xff"); - r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh); + r = connection_edge_process_resolved_cell(edgeconn, msg); tt_int_op(r, OP_EQ, 0); ASSERT_MARK_CALLED(END_STREAM_REASON_DONE| END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, -1, -1); done: + relay_msg_free(msg); UNMOCK(connection_mark_unattached_ap_); UNMOCK(connection_ap_handshake_socks_resolved); } diff --git a/src/test/test_sendme.c b/src/test/test_sendme.c @@ -7,6 +7,7 @@ #define NETWORKSTATUS_PRIVATE #define SENDME_PRIVATE #define RELAY_PRIVATE +#define RELAY_CELL_PRIVATE #include "core/or/circuit_st.h" #include "core/or/or_circuit_st.h" @@ -202,48 +203,6 @@ test_v1_build_cell(void *arg) } static void -test_cell_payload_pad(void *arg) -{ - size_t pad_offset, payload_len, expected_offset; - - (void) arg; - - /* Offset should be 0, not enough room for padding. */ - 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); - - /* Still no room because we keep 4 extra bytes. */ - 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); - - /* We should have 1 byte of padding. Meaning, the offset should be the - * CELL_PAYLOAD_SIZE minus 1 byte. */ - 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); - - /* Now some arbitrary small payload length. The cell size is header + 10 + - * extra 4 bytes we keep so the offset should be there. */ - 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); - - /* Data length of 0. */ - 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; @@ -275,9 +234,11 @@ static void test_package_payload_len(void *arg) { (void)arg; - /* this is not a real circuit: it only has the fields needed for this - * test. */ - circuit_t *c = tor_malloc_zero(sizeof(circuit_t)); + or_circuit_t *or_circ = or_circuit_new(0, NULL); + crypt_path_t *cpath = NULL; + circuit_t *c = TO_CIRCUIT(or_circ); + + or_circ->relay_cell_format = RELAY_CELL_FORMAT_V0; /* check initial conditions. */ circuit_reset_sendme_randomness(c); @@ -288,15 +249,16 @@ test_package_payload_len(void *arg) /* We have a bunch of cells before we need to send randomness, so the first * few can be packaged full. */ int initial = c->send_randomness_after_n_cells; - size_t n = connection_edge_get_inbuf_bytes_to_package(10000, 0, c); + size_t n = connection_edge_get_inbuf_bytes_to_package(10000, 0, c, cpath); tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n); - n = connection_edge_get_inbuf_bytes_to_package(95000, 1, c); + n = connection_edge_get_inbuf_bytes_to_package(95000, 1, c, cpath); tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n); tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2); /* If package_partial isn't set, we won't package a partially full cell at * all. */ - n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 0, c); + n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 0, + c, cpath); tt_int_op(n, OP_EQ, 0); /* no change in our state, since nothing was sent. */ tt_assert(! c->have_sent_sufficiently_random_cell); @@ -305,13 +267,15 @@ test_package_payload_len(void *arg) /* If package_partial is set and the partial cell is not going to have * _enough_ randomness, we package it, but we don't consider ourselves to * have sent a sufficiently random cell. */ - n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 1, c); + n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 1, + c, cpath); 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); /* Make sure we set have_set_sufficiently_random_cell as appropriate. */ - n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-64, 1, c); + n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-64, 1, + c, cpath); 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); @@ -320,7 +284,7 @@ test_package_payload_len(void *arg) * sent a sufficiently random cell, we will not force this one to have a gap. */ c->send_randomness_after_n_cells = 0; - n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c); + n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c, cpath); tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE); /* Now these will be reset. */ tt_assert(! c->have_sent_sufficiently_random_cell); @@ -329,7 +293,7 @@ test_package_payload_len(void *arg) /* What would happen if we hadn't sent a sufficiently random cell? */ c->send_randomness_after_n_cells = 0; - n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c); + n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c, cpath); const size_t reduced_payload_size = RELAY_PAYLOAD_SIZE - 4 - 16; tt_int_op(n, OP_EQ, reduced_payload_size); /* Now these will be reset. */ @@ -341,11 +305,12 @@ test_package_payload_len(void *arg) * package_partial==0 should mean we accept that many bytes. */ c->send_randomness_after_n_cells = 0; - n = connection_edge_get_inbuf_bytes_to_package(reduced_payload_size, 0, c); + n = connection_edge_get_inbuf_bytes_to_package(reduced_payload_size, 0, + c, cpath); tt_int_op(n, OP_EQ, reduced_payload_size); done: - tor_free(c); + circuit_free(c); } /* Check that circuit_sendme_is_next works with a window of 1000, @@ -399,8 +364,6 @@ struct testcase_t sendme_tests[] = { 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 },