#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?
* 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;
/* 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;
}
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).
*
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);
/* 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;
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;
}
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);
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) */
-
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 ***************************/
src/core/or/protover.c \
src/core/or/reasons.c \
src/core/or/relay.c \
- src/core/or/relay_cell.c \
src/core/or/relay_msg.c \
src/core/or/scheduler.c \
src/core/or/scheduler_kist.c \
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. */
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;
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.
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 *
const char *filename, int lineno))
{
cell_t cell;
- relay_header_t rh;
cell_direction_t cell_direction;
circuit_t *circ = orig_circ;
tor_assert(circ);
+ size_t msg_body_len;
{
relay_cell_fmt_t cell_format = relay_msg_get_format(circ, cpath_layer);
relay_msg_t msg;
// There is no need to copy the payload here, so long as we don't
// free it.
msg.body = (uint8_t *) payload;
+ msg_body_len = msg.length;
if (relay_msg_encode_cell(cell_format, &msg, &cell) < 0) {
// This already gave a BUG warning, so no need to log.
/* 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,
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,
+++ /dev/null
-/* Copyright (c) 2023, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file relay_cell.c
- * \brief This file handles most of the encoding and parsing of relay cells for
- * all supported versions.
- **/
-
-#include <stddef.h>
-#include <stdint.h>
-#define RELAY_CELL_PRIVATE
-
-#include "core/or/relay_cell.h"
-#include "core/or/relay.h"
-
-#include "lib/arch/bytes.h"
-#include "lib/crypt_ops/crypto_rand.h"
-#include "lib/log/util_bug.h"
-
-/*
- * NOTE: As a starter of this file, it is important to note that trunnel is not
- * used due to its heavy reliance on memory allocation. Parsing and encoding
- * cells is a critical piece of the fast path and MUST be done with little
- * as possible memory allocation or copy.
- *
- * And so, you will notice the direct access into a cell_t memory and relying
- * on offset instead of copying data into an object representing a header.
- */
-
-/*
- * Relay cell header static values.
- *
- * We don't copy the header back into a structure for performance reason. When
- * accessing the header, we simply use offset within the cell_t payload.
- *
- * NOTE: We might want to move to a nicer static data structure containing all
- * these and indexed by version but for now with the very few relay cell
- * protocol and considering the future of C-tor this is simpler and enough.
- */
-
-/* The "recognized" field by version. */
-#define RECOGNIZED_OFFSET_V0 (1)
-#define RECOGNIZED_OFFSET_V1 (0)
-
-/* The "digest" field by version. */
-#define DIGEST_OFFSET_V0 (5)
-#define DIGEST_OFFSET_V1 (2)
-
-/**
- * TODO #41051: Remove this entirely.
- *
- * I've moved this functionality into relay_msg.c, where it lives
- * more happily. This function shouldn't have any callsites left
- * at the end of this branch.
- **/
-void
-relay_cell_pad_payload(cell_t *cell, size_t data_len)
-{
- (void)cell;
- (void)data_len;
-}
-
-/** Return true iff the given cell recognized field is zero. */
-bool
-relay_cell_is_recognized(const cell_t *cell)
-{
- switch (cell->relay_cell_proto) {
- case 0: return get_uint16(cell->payload + RECOGNIZED_OFFSET_V0) == 0;
- case 1: return get_uint16(cell->payload + RECOGNIZED_OFFSET_V1) == 0;
- default:
- /* Reaching this means we've failed to validate the supported relay cell
- * version. */
- tor_fragile_assert();
- return false;
- }
-}
-
-/** Return a pointer from inside the given cell pointing to the start of the
- * relay cell digest for the given protocol version.
- *
- * This is part of the fast path. No memory allocation. */
-uint8_t *
-relay_cell_get_digest(cell_t *cell)
-{
- switch (cell->relay_cell_proto) {
- case 0: return cell->payload + DIGEST_OFFSET_V0;
- case 1: return cell->payload + DIGEST_OFFSET_V1;
- default:
- /* Reaching this means we've failed to validate the supported relay cell
- * version. Return the start of the payload, it will simply never
- * validate and ultimately will close the circuit. */
- tor_fragile_assert();
- return cell->payload;
- }
-}
-
-/** Return the relay cell digest length based on the given protocol version. */
-size_t
-relay_cell_get_digest_len(const cell_t *cell)
-{
-/* Specified in tor-spec.txt */
-#define RELAY_CELL_DIGEST_LEN_V0 (4)
-#define RELAY_CELL_DIGEST_LEN_V1 (14)
-
- switch (cell->relay_cell_proto) {
- case 0: return RELAY_CELL_DIGEST_LEN_V0;
- case 1: return RELAY_CELL_DIGEST_LEN_V1;
- default:
- /* Reaching this means we've failed to validate the supported relay cell
- * version. This length will simply never validate and ultimately the
- * circuit will be closed. */
- tor_fragile_assert();
- return 0;
- }
-}
-
-/** Set the given cell_digest value into the cell for the given relay cell
- * protocol version.
- *
- * This is part of the fast path. No memory allocation. */
-void
-relay_cell_set_digest(cell_t *cell, uint8_t *new_cell_digest)
-{
- uint8_t *cell_digest_ptr = relay_cell_get_digest(cell);
- size_t cell_digest_len = relay_cell_get_digest_len(cell);
-
- memcpy(cell_digest_ptr, new_cell_digest, cell_digest_len);
-}
#include "core/or/cell_st.h"
-/* TODO #41051: Most of these functions no longer make sense under CGO,
- * and we are only going to use the new proto format with CGO. */
-
-/* Getters. */
-bool relay_cell_is_recognized(const cell_t *cell);
-uint8_t *relay_cell_get_digest(cell_t *cell);
-size_t relay_cell_get_digest_len(const cell_t *cell);
-
-/* Setters. */
-void relay_cell_set_digest(cell_t *cell, uint8_t *cell_digest);
-void relay_cell_pad_payload(cell_t *cell, size_t data_len);
+/* TODO #41051: Fold this file into relay_msg.h */
/*
* NOTE: The following are inlined for performance reasons. These values are