Tor 0.4.9.2-alpha-dev
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
relay_msg.c
Go to the documentation of this file.
1/* Copyright (c) 2023, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * \file relay_msg.c
6 * \brief Encoding relay messages into cells.
7 **/
8
9#define RELAY_MSG_PRIVATE
10
11#include "app/config/config.h"
12
13#include "core/or/cell_st.h"
14#include "core/or/circuitlist.h"
15#include "core/or/relay.h"
16#include "core/or/relay_msg.h"
18
19#include "core/or/cell_st.h"
22#include "core/or/or_circuit_st.h"
23
24/*
25 * Public API
26 */
27
28/** Free the given relay message. */
29void
31{
32 if (!msg) {
33 return;
34 }
35 tor_free(msg);
36}
37
38/** Clear a relay message as in free its content and reset all fields to 0.
39 * This is useful for stack allocated memory. */
40void
42{
43 tor_assert(msg);
44 memset(msg, 0, sizeof(*msg));
45}
46
47/* Positions of fields within a v0 message. */
48#define V0_CMD_OFFSET 0
49#define V0_STREAM_ID_OFFSET 3
50#define V0_LEN_OFFSET 9
51#define V0_PAYLOAD_OFFSET 11
52
53/* Positions of fields within a v1 message. */
54#define V1_CMD_OFFSET 16
55#define V1_LEN_OFFSET 17
56#define V1_STREAM_ID_OFFSET 19
57#define V1_PAYLOAD_OFFSET_NO_STREAM_ID 19
58#define V1_PAYLOAD_OFFSET_WITH_STREAM_ID 21
59
60/** Allocate a new relay message and copy the content of the given message.
61 *
62 * This message allocation _will_ own its body, even if the original did not.
63 *
64 * Requires that msg is well-formed, and that its length is within
65 * allowable bounds.
66 **/
69{
70 tor_assert(msg->length <= RELAY_PAYLOAD_SIZE_MAX);
71 void *alloc = tor_malloc_zero(sizeof(relay_msg_t) + msg->length);
72 relay_msg_t *new_msg = alloc;
73 uint8_t *body = ((uint8_t*)alloc) + sizeof(relay_msg_t);
74
75 memcpy(new_msg, msg, sizeof(*msg));
76 new_msg->body = body;
77 memcpy(body, msg->body, msg->length);
78
79 return new_msg;
80}
81
82/* Add random bytes to the unused portion of the payload, to foil attacks
83 * where the other side can predict all of the bytes in the payload and thus
84 * compute the authenticated SENDME cells without seeing the traffic. See
85 * proposal 289. */
86static void
87relay_cell_pad(cell_t *cell, size_t end_of_message)
88{
89 // We add 4 bytes of zero before padding, for forward-compatibility.
90 const size_t skip = 4;
91
92 if (end_of_message + skip >= CELL_PAYLOAD_SIZE) {
93 /* nothing to do. */
94 return;
95 }
96
98 &cell->payload[end_of_message + skip],
99 CELL_PAYLOAD_SIZE - (end_of_message + skip));
100}
101
102/** Encode the relay message in 'msg' into cell, according to the
103 * v0 rules. */
104static int
106 cell_t *cell_out)
107{
108 size_t maxlen =
110 IF_BUG_ONCE(msg->length > maxlen) {
111 return -1;
112 }
113
114 uint8_t *out = cell_out->payload;
115
116 out[V0_CMD_OFFSET] = (uint8_t) msg->command;
117 set_uint16(out+V0_STREAM_ID_OFFSET, htons(msg->stream_id));
118 set_uint16(out+V0_LEN_OFFSET, htons(msg->length));
119 memcpy(out + RELAY_HEADER_SIZE_V0, msg->body, msg->length);
120 relay_cell_pad(cell_out, RELAY_HEADER_SIZE_V0 + msg->length);
121
122 return 0;
123}
124
125/** Encode the relay message in 'msg' into cell, according to the
126 * v0 rules. */
127static int
129 cell_t *cell_out)
130{
131 bool expects_streamid = relay_cmd_expects_streamid_in_v1(msg->command);
132 size_t maxlen =
134 IF_BUG_ONCE(msg->length > maxlen) {
135 return -1;
136 }
137
138 uint8_t *out = cell_out->payload;
139 out[V1_CMD_OFFSET] = msg->command;
140 set_uint16(out+V1_LEN_OFFSET, htons(msg->length));
141 size_t payload_offset;
142 if (expects_streamid) {
143 IF_BUG_ONCE(msg->stream_id == 0) {
144 return -1;
145 }
146 set_uint16(out+V1_STREAM_ID_OFFSET, htons(msg->stream_id));
147 payload_offset = V1_PAYLOAD_OFFSET_WITH_STREAM_ID;
148 } else {
149 IF_BUG_ONCE(msg->stream_id != 0) {
150 return -1;
151 }
152
153 payload_offset = V1_PAYLOAD_OFFSET_NO_STREAM_ID;
154 }
155
156 memcpy(out + payload_offset, msg->body, msg->length);
157 relay_cell_pad(cell_out, payload_offset + msg->length);
158 return 0;
159}
160
161/** Try to decode 'cell' into a V0 relay message.
162 *
163 * Return 0 on success, -1 on error.
164 */
165static int
167{
168 memset(out, 0, sizeof(relay_msg_t));
169 out->is_relay_early = (cell->command == CELL_RELAY_EARLY);
170
171 const uint8_t *body = cell->payload;
172 out->command = get_uint8(body + V0_CMD_OFFSET);
173 out->stream_id = ntohs(get_uint16(body + V0_STREAM_ID_OFFSET));
174 out->length = ntohs(get_uint16(body + V0_LEN_OFFSET));
175
176 if (out->length > CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE_V0) {
177 return -1;
178 }
179 out->body = body + V0_PAYLOAD_OFFSET;
180
181 return 0;
182}
183
184/** Try to decode 'cell' into a V1 relay message.
185 *
186 * Return 0 on success, -1 on error.=
187 */
188static int
190{
191 memset(out, 0, sizeof(relay_msg_t));
192 out->is_relay_early = (cell->command == CELL_RELAY_EARLY);
193
194 const uint8_t *body = cell->payload;
195 out->command = get_uint8(body + V1_CMD_OFFSET);
196 if (! is_known_relay_command(out->command))
197 return -1;
198
199 out->length = ntohs(get_uint16(body + V1_LEN_OFFSET));
200 size_t payload_offset;
201 if (relay_cmd_expects_streamid_in_v1(out->command)) {
202 out->stream_id = ntohs(get_uint16(body + V1_STREAM_ID_OFFSET));
203 payload_offset = V1_PAYLOAD_OFFSET_WITH_STREAM_ID;
204 } else {
205 payload_offset = V1_PAYLOAD_OFFSET_NO_STREAM_ID;
206 }
207
208 if (out->length > CELL_PAYLOAD_SIZE - payload_offset)
209 return -1;
210 out->body = body + payload_offset;
211
212 return 0;
213}
214/**
215 * Encode 'msg' into 'cell' according to the rules of 'format'.
216 *
217 * Does not set any "recognized", "digest" or "tag" fields,
218 * since those are necessarily part of the crypto logic.
219 *
220 * Clears the circuit ID on the cell.
221 *
222 * Return 0 on success, and -1 if 'msg' is not well-formed.
223 */
224int
226 const relay_msg_t *msg,
227 cell_t *cell_out)
228{
229 memset(cell_out, 0, sizeof(cell_t));
230 cell_out->command = msg->is_relay_early ?
231 CELL_RELAY_EARLY : CELL_RELAY;
232
233 switch (format) {
235 return encode_v0_cell(msg, cell_out);
237 return encode_v1_cell(msg, cell_out);
238 default:
240 return -1;
241 }
242}
243
244/**
245 * Decode 'cell' (which must be RELAY or RELAY_EARLY) into a newly allocated
246 * 'relay_msg_t'.
247 *
248 * Note that the resulting relay_msg_t will have a reference to 'cell'.
249 * Do not change 'cell' while the resulting message is still in use!
250 *
251 * Return -1 on error, and 0 on success.
252 */
253int
255 const cell_t *cell,
256 relay_msg_t *msg_out)
257{
258 switch (format) {
260 return decode_v0_cell(cell, msg_out);
262 return decode_v1_cell(cell, msg_out);
263 default:
265 return -1;
266 }
267}
268
269/**
270 * As relay_msg_decode_cell_in_place, but allocate a new relay_msg_t
271 * on success.
272 *
273 * Return NULL on error.
274 */
277 const cell_t *cell)
278{
279 relay_msg_t *msg = tor_malloc(sizeof(relay_msg_t));
280 if (relay_msg_decode_cell_in_place(format, cell, msg) < 0) {
281 relay_msg_free(msg);
282 return NULL;
283 } else {
284 return msg;
285 }
286}
static void set_uint16(void *cp, uint16_t v)
Definition: bytes.h:78
static uint16_t get_uint16(const void *cp)
Definition: bytes.h:42
static uint8_t get_uint8(const void *cp)
Definition: bytes.h:23
Fixed-size cell structure.
Header file for circuitlist.c.
Header file for config.c.
Path structures for origin circuits.
Common functions for using (pseudo-)random number generators.
crypto_fast_rng_t * get_thread_fast_rng(void)
void crypto_fast_rng_getbytes(crypto_fast_rng_t *rng, uint8_t *out, size_t n)
#define tor_free(p)
Definition: malloc.h:56
#define CELL_PAYLOAD_SIZE
Definition: or.h:520
static bool is_known_relay_command(const uint8_t cmd)
Definition: or.h:230
#define RELAY_HEADER_SIZE_V0
Definition: or.h:554
#define RELAY_PAYLOAD_SIZE_MAX
Definition: or.h:567
relay_cell_fmt_t
Definition: or.h:529
@ RELAY_CELL_FORMAT_V1
Definition: or.h:533
@ RELAY_CELL_FORMAT_V0
Definition: or.h:531
Header file for relay.c.
static int encode_v0_cell(const relay_msg_t *msg, cell_t *cell_out)
Definition: relay_msg.c:105
int relay_msg_encode_cell(relay_cell_fmt_t format, const relay_msg_t *msg, cell_t *cell_out)
Definition: relay_msg.c:225
static int decode_v1_cell(const cell_t *cell, relay_msg_t *out)
Definition: relay_msg.c:189
void relay_msg_clear(relay_msg_t *msg)
Definition: relay_msg.c:41
relay_msg_t * relay_msg_copy(const relay_msg_t *msg)
Definition: relay_msg.c:68
static int encode_v1_cell(const relay_msg_t *msg, cell_t *cell_out)
Definition: relay_msg.c:128
static int decode_v0_cell(const cell_t *cell, relay_msg_t *out)
Definition: relay_msg.c:166
void relay_msg_free_(relay_msg_t *msg)
Definition: relay_msg.c:30
int relay_msg_decode_cell_in_place(relay_cell_fmt_t format, const cell_t *cell, relay_msg_t *msg_out)
Definition: relay_msg.c:254
relay_msg_t * relay_msg_decode_cell(relay_cell_fmt_t format, const cell_t *cell)
Definition: relay_msg.c:276
Header file for relay_msg.c.
static bool relay_cmd_expects_streamid_in_v1(uint8_t relay_command)
Definition: relay_msg.h:44
static size_t relay_cell_max_payload_size(relay_cell_fmt_t format, uint8_t relay_command)
Definition: relay_msg.h:65
A relay message which contains a relay command and parameters, if any, that is from a relay cell.
Definition: cell_st.h:17
uint8_t payload[CELL_PAYLOAD_SIZE]
Definition: cell_st.h:21
uint8_t command
Definition: cell_st.h:19
#define tor_assert(expr)
Definition: util_bug.h:103
#define tor_fragile_assert()
Definition: util_bug.h:278
#define IF_BUG_ONCE(cond)
Definition: util_bug.h:254