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:
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 },