1
//! Implementation for parsing and encoding relay cells
2

            
3
use std::num::NonZeroU16;
4

            
5
use crate::chancell::{BoxedCellBody, CELL_DATA_LEN};
6
use derive_deftly::Deftly;
7
use smallvec::{smallvec, SmallVec};
8
use tor_bytes::{EncodeError, EncodeResult, Error, Result};
9
use tor_bytes::{Reader, Writer};
10
use tor_error::internal;
11
use tor_memquota::derive_deftly_template_HasMemoryCost;
12

            
13
use caret::caret_int;
14
use rand::{CryptoRng, Rng};
15

            
16
#[cfg(feature = "conflux")]
17
pub mod conflux;
18
pub mod extend;
19
mod extlist;
20
#[cfg(feature = "hs")]
21
pub mod hs;
22
pub mod msg;
23
#[cfg(feature = "experimental-udp")]
24
pub mod udp;
25

            
26
caret_int! {
27
    /// A command that identifies the type of a relay cell
28
    #[derive(Deftly)]
29
    #[derive_deftly(HasMemoryCost)]
30
    pub struct RelayCmd(u8) {
31
        /// Start a new stream
32
        BEGIN = 1,
33
        /// Data on a stream
34
        DATA = 2,
35
        /// Close a stream
36
        END = 3,
37
        /// Acknowledge a BEGIN; stream is open
38
        CONNECTED = 4,
39
        /// Used for flow control
40
        SENDME = 5,
41
        /// Extend a circuit to a new hop; deprecated
42
        EXTEND = 6,
43
        /// Reply to EXTEND handshake; deprecated
44
        EXTENDED = 7,
45
        /// Partially close a circuit
46
        TRUNCATE = 8,
47
        /// Circuit has been partially closed
48
        TRUNCATED = 9,
49
        /// Padding cell
50
        DROP = 10,
51
        /// Start a DNS lookup
52
        RESOLVE = 11,
53
        /// Reply to a DNS lookup
54
        RESOLVED = 12,
55
        /// Start a directory stream
56
        BEGIN_DIR = 13,
57
        /// Extend a circuit to a new hop
58
        EXTEND2 = 14,
59
        /// Reply to an EXTEND2 cell.
60
        EXTENDED2 = 15,
61

            
62
        /// NOTE: UDP command are reserved but only used with experimental-udp feature
63

            
64
        /// UDP: Start of a stream
65
        CONNECT_UDP = 16,
66
        /// UDP: Acknowledge a CONNECT_UDP. Stream is open.
67
        CONNECTED_UDP = 17,
68
        /// UDP: Data on a UDP stream.
69
        DATAGRAM = 18,
70

            
71
        /// CONFLUX: Link circuits together at the receiving endpoint.
72
        CONFLUX_LINK = 19,
73
        /// CONFLUX: Confirm that the circuits were linked.
74
        CONFLUX_LINKED = 20,
75
        /// CONFLUX: Acknowledge the linkage of the circuits, for RTT measurement.
76
        CONFLUX_LINKED_ACK = 21,
77
        /// CONFLUX: Switch to another leg in an already linked circuit construction.
78
        CONFLUX_SWITCH = 22,
79

            
80
        /// HS: establish an introduction point.
81
        ESTABLISH_INTRO = 32,
82
        /// HS: establish a rendezvous point.
83
        ESTABLISH_RENDEZVOUS = 33,
84
        /// HS: send introduction (client to introduction point)
85
        INTRODUCE1 = 34,
86
        /// HS: send introduction (introduction point to service)
87
        INTRODUCE2 = 35,
88
        /// HS: connect rendezvous point (service to rendezvous point)
89
        RENDEZVOUS1 = 36,
90
        /// HS: connect rendezvous point (rendezvous point to client)
91
        RENDEZVOUS2 = 37,
92
        /// HS: Response to ESTABLISH_INTRO
93
        INTRO_ESTABLISHED = 38,
94
        /// HS: Response to ESTABLISH_RENDEZVOUS
95
        RENDEZVOUS_ESTABLISHED = 39,
96
        /// HS: Response to INTRODUCE1 from introduction point to client
97
        INTRODUCE_ACK = 40,
98

            
99
        /// Padding: declare what kind of padding we want
100
        PADDING_NEGOTIATE = 41,
101
        /// Padding: reply to a PADDING_NEGOTIATE
102
        PADDING_NEGOTIATED = 42,
103
    }
104
}
105

            
106
/// Possible requirements on stream IDs for a relay command.
107
enum StreamIdReq {
108
    /// Can only be used with a stream ID of 0
109
    WantNone,
110
    /// Can only be used with a stream ID that isn't 0
111
    WantSome,
112
    /// Can be used with any stream ID.
113
    ///
114
    /// This result is impossible with `RelayCellFormat::V1`.
115
    Any,
116
    /// Unrecognized; might be used with a stream ID or without.
117
    Unrecognized,
118
}
119

            
120
impl RelayCmd {
121
    /// Check whether this command requires a certain kind of
122
    /// StreamId in the provided `format`, and return a corresponding StreamIdReq.
123
    ///
124
    /// If `format` is None, return a result that is correct for _any_ version.
125
6050
    fn expects_streamid(self, format: Option<RelayCellFormat>) -> StreamIdReq {
126
6050
        match self {
127
            RelayCmd::BEGIN
128
            | RelayCmd::DATA
129
            | RelayCmd::END
130
            | RelayCmd::CONNECTED
131
            | RelayCmd::RESOLVE
132
            | RelayCmd::RESOLVED
133
3905
            | RelayCmd::BEGIN_DIR => StreamIdReq::WantSome,
134
            // NOTE: Even when a RelayCmd is not implemented (like these UDP-based commands),
135
            // we need to implement expects_streamid() unconditionally.
136
            // Otherwise we leak more information than necessary
137
            // when parsing RelayCellFormat::V1 cells.
138
            RelayCmd::CONNECT_UDP | RelayCmd::CONNECTED_UDP | RelayCmd::DATAGRAM => {
139
                StreamIdReq::WantSome
140
            }
141
            RelayCmd::EXTEND
142
            | RelayCmd::EXTENDED
143
            | RelayCmd::TRUNCATE
144
            | RelayCmd::TRUNCATED
145
            | RelayCmd::DROP
146
            | RelayCmd::EXTEND2
147
            | RelayCmd::EXTENDED2
148
            | RelayCmd::CONFLUX_LINK
149
            | RelayCmd::CONFLUX_LINKED
150
            | RelayCmd::CONFLUX_LINKED_ACK
151
            | RelayCmd::CONFLUX_SWITCH
152
            | RelayCmd::ESTABLISH_INTRO
153
            | RelayCmd::ESTABLISH_RENDEZVOUS
154
            | RelayCmd::INTRODUCE1
155
            | RelayCmd::INTRODUCE2
156
            | RelayCmd::RENDEZVOUS1
157
            | RelayCmd::RENDEZVOUS2
158
            | RelayCmd::INTRO_ESTABLISHED
159
            | RelayCmd::RENDEZVOUS_ESTABLISHED
160
1485
            | RelayCmd::INTRODUCE_ACK => StreamIdReq::WantNone,
161
275
            RelayCmd::SENDME => match format {
162
                // There are no stream-level SENDMES in V1, since CC is mandatory.
163
                // Further, the 'Any' result is not possible with V1, since
164
                // we need be able to decide whether a stream ID is present
165
                // from the value of the command.
166
275
                Some(RelayCellFormat::V1) => StreamIdReq::WantNone,
167
                // In V0, CC is not mandatory, so stream-level SENDMES are possible.
168
                Some(RelayCellFormat::V0) => StreamIdReq::Any,
169
                // When we're checking for general compatibility, we need to allow V0 or V1.
170
330
                None => StreamIdReq::Any,
171
            },
172
55
            _ => StreamIdReq::Unrecognized,
173
        }
174
6050
    }
175
    /// Return true if this command is one that accepts the particular
176
    /// stream ID `id`.
177
    ///
178
    /// Note that this method does not consider the [`RelayCellFormat`] in use:
179
    /// it will return "true" for _any_ stream ID if the command is `SENDME`,
180
    /// and if the command is unrecognized.
181
4950
    pub fn accepts_streamid_val(self, id: Option<StreamId>) -> bool {
182
4950
        match self.expects_streamid(None) {
183
1210
            StreamIdReq::WantNone => id.is_none(),
184
3410
            StreamIdReq::WantSome => id.is_some(),
185
330
            StreamIdReq::Any => true,
186
            StreamIdReq::Unrecognized => true,
187
        }
188
4950
    }
189
}
190

            
191
/// Identify a single stream on a circuit.
192
///
193
/// These identifiers are local to each hop on a circuit.
194
/// This can't be zero; if you need something that can be zero in the protocol,
195
/// use `Option<StreamId>`.
196
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Hash, Deftly)]
197
#[derive_deftly(HasMemoryCost)]
198
pub struct StreamId(NonZeroU16);
199

            
200
impl From<NonZeroU16> for StreamId {
201
27005
    fn from(id: NonZeroU16) -> Self {
202
27005
        Self(id)
203
27005
    }
204
}
205

            
206
impl From<StreamId> for NonZeroU16 {
207
13728
    fn from(id: StreamId) -> NonZeroU16 {
208
13728
        id.0
209
13728
    }
210
}
211

            
212
impl From<StreamId> for u16 {
213
110
    fn from(id: StreamId) -> u16 {
214
110
        id.0.get()
215
110
    }
216
}
217

            
218
impl std::fmt::Display for StreamId {
219
1155
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
220
1155
        self.0.fmt(f)
221
1155
    }
222
}
223

            
224
impl StreamId {
225
    /// Creates a `StreamId` for non-zero `stream_id`.
226
    ///
227
    /// Returns `None` when `stream_id` is zero. Messages with a zero/None stream ID
228
    /// apply to the circuit as a whole instead of a particular stream.
229
87670
    pub fn new(stream_id: u16) -> Option<Self> {
230
87670
        NonZeroU16::new(stream_id).map(Self)
231
87670
    }
232

            
233
    /// Convenience function to convert to a `u16`; `None` is mapped to 0.
234
86075
    pub fn get_or_zero(stream_id: Option<Self>) -> u16 {
235
86075
        match stream_id {
236
83160
            Some(stream_id) => stream_id.0.get(),
237
2915
            None => 0,
238
        }
239
86075
    }
240
}
241

            
242
/// Specifies which encoding version of RelayCell to use.
243
#[non_exhaustive]
244
#[derive(Copy, Clone, Debug)]
245
pub enum RelayCellFormat {
246
    /// This is the "legacy" pre-prop340 format. No packing or fragmentation.
247
    V0,
248
    /// A "transitional" format for use with Counter Galois Onion encryption.
249
    ///
250
    /// It provides a 16-byte tag field, and a simplified layout for the rest of
251
    /// the cell.
252
    V1,
253
}
254

            
255
/// Internal decoder state.
256
#[derive(Clone, Debug)]
257
enum RelayCellDecoderInternal {
258
    /// Internal state for `RelayCellFormat::V0`
259
    V0,
260
    /// Internal state for `RelayCellFormat::V1`
261
    V1,
262
}
263

            
264
// TODO prop340: We should also fuzz RelayCellDecoder, but not in this fuzzer.
265

            
266
/// Decodes a stream of relay cell bodies into `UnparsedRelayMsg`s.
267
#[derive(Clone, Debug)]
268
pub struct RelayCellDecoder {
269
    /// Internal representation.
270
    internal: RelayCellDecoderInternal,
271
}
272

            
273
impl RelayCellDecoder {
274
    /// Returns a new `Decoder`, handling a stream of relay cells
275
    /// of the given `version`.
276
87285
    pub fn new(version: RelayCellFormat) -> Self {
277
87285
        match version {
278
86680
            RelayCellFormat::V0 => Self {
279
86680
                internal: RelayCellDecoderInternal::V0,
280
86680
            },
281
605
            RelayCellFormat::V1 => Self {
282
605
                internal: RelayCellDecoderInternal::V1,
283
605
            },
284
        }
285
87285
    }
286
    /// Parse a RELAY or RELAY_EARLY cell body.
287
    ///
288
    /// Requires that the cryptographic checks on the message have already been
289
    /// performed
290
80795
    pub fn decode(&mut self, cell: BoxedCellBody) -> Result<RelayCellDecoderResult> {
291
80795
        let msg_internal = match &self.internal {
292
80190
            RelayCellDecoderInternal::V0 => UnparsedRelayMsgInternal::V0(cell),
293
605
            RelayCellDecoderInternal::V1 => UnparsedRelayMsgInternal::V1(cell),
294
        };
295
        Ok(RelayCellDecoderResult {
296
80795
            msgs: smallvec![UnparsedRelayMsg {
297
                internal: msg_internal
298
            }],
299
80795
            incomplete: None,
300
80795
        })
301
80795
    }
302
    /// Returns the `IncompleteRelayMsgInfo` describing the partial
303
    /// (fragmented) relay message at the end of the so-far-processed relay cell
304
    /// stream.
305
    pub fn incomplete_info(&self) -> Option<IncompleteRelayMsgInfo> {
306
        match &self.internal {
307
            // V0 and V1 don't support fragmentation, so there is never a pending fragment.
308
            RelayCellDecoderInternal::V0 | RelayCellDecoderInternal::V1 => None,
309
        }
310
    }
311
}
312

            
313
/// Result of calling `RelayCellDecoder::decode`.
314
#[derive(Debug)]
315
pub struct RelayCellDecoderResult {
316
    /// Complete messages obtained by decoding the cell. i.e. messages
317
    /// that were completely contained within the cell, or for which the cell
318
    /// contained the final fragment.
319
    msgs: SmallVec<[UnparsedRelayMsg; 1]>,
320
    /// Description of the partial message at the end of the cell, if any.
321
    incomplete: Option<IncompleteRelayMsgInfo>,
322
}
323

            
324
impl RelayCellDecoderResult {
325
    /// Returns a non-empty iterator over commands in relay messages that the
326
    /// cell producing this result contained *any* part of. i.e. this includes
327
    /// the command of "head", "middle", and/or "tail" message fragments that
328
    /// were in the cell.
329
4730
    pub fn cmds(&self) -> impl Iterator<Item = RelayCmd> + '_ {
330
4816
        let complete_msg_cmds = self.msgs.iter().map(|m| m.cmd());
331
4730
        let partial_msg_cmd = self.incomplete.as_ref().map(|c| c.cmd());
332
4730
        complete_msg_cmds.chain(partial_msg_cmd)
333
4730
    }
334
    /// Converts `self` to an iterator over the complete messages, and metadata
335
    /// about the trailing incomplete message (as for `Self::incomplete_info`),
336
    /// if any.
337
80795
    pub fn into_parts(
338
80795
        self,
339
80795
    ) -> (
340
80795
        impl Iterator<Item = UnparsedRelayMsg>,
341
80795
        Option<IncompleteRelayMsgInfo>,
342
80795
    ) {
343
80795
        (self.msgs.into_iter(), self.incomplete)
344
80795
    }
345
    /// Returns the `IncompleteRelayMsgInfo` describing the incomplete
346
    /// relay message that this cell contained a fragment of, if any.
347
    ///
348
    /// Note that:
349
    /// * This does not describe a fragment that includes the end of the relay
350
    ///   message, since the message is then complete.
351
    /// * This *does* include a fragment that continues, but does not complete,
352
    ///   a message started in an earlier relay cell.
353
    /// * There is at most one such incomplete relay message, since no current
354
    ///   relay cell format supports starting a new message before completing the
355
    ///   previous one.
356
    pub fn incomplete_info(&self) -> Option<IncompleteRelayMsgInfo> {
357
        self.incomplete.clone()
358
    }
359
}
360

            
361
/// Information about a relay message for which we don't yet have the complete body.
362
#[derive(Clone, Debug)]
363
pub struct IncompleteRelayMsgInfo {
364
    /// The message's command.
365
    cmd: RelayCmd,
366
    /// The message's stream ID, if any.
367
    stream_id: Option<StreamId>,
368
    /// The total number of bytes in the body of the message.
369
    total_msg_len: usize,
370
    /// The number of bytes of the body of the message that we've decoded so
371
    /// far.
372
    num_bytes_present: usize,
373
}
374

            
375
impl IncompleteRelayMsgInfo {
376
    /// Returns the message's command.
377
    pub fn cmd(&self) -> RelayCmd {
378
        self.cmd
379
    }
380
    /// Returns the message's `StreamId`, if any.
381
    pub fn stream_id(&self) -> Option<StreamId> {
382
        self.stream_id
383
    }
384
    /// Returns the total size of the complete message body.
385
    pub fn total_msg_len(&self) -> usize {
386
        self.total_msg_len
387
    }
388
    /// Returns the number of bytes of the message body that we have so far.
389
    pub fn num_bytes_present(&self) -> usize {
390
        self.num_bytes_present
391
    }
392
    /// Returns the number of bytes of the message body that we still need.
393
    pub fn num_bytes_missing(&self) -> usize {
394
        self.total_msg_len - self.num_bytes_present
395
    }
396
}
397

            
398
/// Internal representation of an `UnparsedRelayMsg`.
399
#[derive(Clone, Debug, Deftly)]
400
#[derive_deftly(HasMemoryCost)]
401
enum UnparsedRelayMsgInternal {
402
    /// For `RelayCellFormat::V0` we can avoid copying data around by just
403
    /// storing the original cell body here.
404
    // NOTE: we could also have a separate command and stream ID field here, but
405
    // we expect to be working with a TON of these, so we will be mildly
406
    // over-optimized and just peek into the body.
407
    //
408
    // It *is* a bit ugly to have to encode so much knowledge about the format in
409
    // different functions here, but that information shouldn't leak out of this module.
410
    V0(BoxedCellBody),
411

            
412
    /// For `V1` we can also avoid copies, since there is still exactly one
413
    /// relay message per cell.
414
    V1(BoxedCellBody),
415
}
416

            
417
/// An enveloped relay message that has not yet been fully parsed, but where we
418
/// have access to the command, stream ID, and payload data length for dispatching
419
/// and congestion control purposes.
420
#[derive(Clone, Debug, Deftly)]
421
#[derive_deftly(HasMemoryCost)]
422
pub struct UnparsedRelayMsg {
423
    /// The internal representation.
424
    internal: UnparsedRelayMsgInternal,
425
}
426

            
427
/// Position of the stream ID within the V0 cell body.
428
const STREAM_ID_OFFSET_V0: usize = 3;
429

            
430
/// Position of the stream ID within the V1 cell body, if it is present.
431
const STREAM_ID_OFFSET_V1: usize = 16 + 1 + 2; // tag, command, length.
432

            
433
/// Position of the payload data length within the V0 cell body.
434
const LENGTH_OFFSET_V0: usize = 1 + 2 + 2 + 4; // command, recognized, stream_id, digest.
435

            
436
/// Position of the payload data length within the V1 cell body.
437
const LENGTH_OFFSET_V1: usize = 16 + 1; // tag, command.
438

            
439
impl UnparsedRelayMsg {
440
    /// Wrap a BoxedCellBody as an UnparsedRelayMsg.
441
    ///
442
    /// Fails if the body doesn't correspond to exactly one relay message, but
443
    /// doesn't parse the message itself.
444
    ///
445
    /// Non-test code should generally use `RelayCellDecoder` instead.
446
    // Ideally we'd make this `#[cfg(test)]`, but then we wouldn't be able
447
    // to use it in integration tests.
448
    // https://github.com/rust-lang/rust/issues/84629
449
76065
    pub fn from_singleton_body(version: RelayCellFormat, body: BoxedCellBody) -> Result<Self> {
450
76065
        let mut decoder = RelayCellDecoder::new(version);
451
76065
        let res = decoder.decode(body)?;
452
76065
        let (mut msgs, incomplete) = res.into_parts();
453
76065
        let Some(msg) = msgs.next() else {
454
            // There was no complete message in the cell.
455
            return Err(Error::MissingData);
456
        };
457
76065
        if incomplete.is_some() {
458
            // There was an incomplete message at the end of the cell.
459
            return Err(Error::ExtraneousBytes);
460
76065
        }
461
76065
        if msgs.next().is_some() {
462
            // There was more than one message in the cell.
463
            return Err(Error::ExtraneousBytes);
464
76065
        }
465
76065
        Ok(msg)
466
76065
    }
467

            
468
    /// Return the command for this cell.
469
30965
    pub fn cmd(&self) -> RelayCmd {
470
30965
        match &self.internal {
471
30525
            UnparsedRelayMsgInternal::V0(body) => {
472
                /// Position of the command within the v0 cell body.
473
                const CMD_OFFSET: usize = 0;
474
30525
                body[CMD_OFFSET].into()
475
            }
476
440
            UnparsedRelayMsgInternal::V1(body) => {
477
                /// Position of the command within the v1 body.
478
                const CMD_OFFSET: usize = 16;
479
440
                body[CMD_OFFSET].into()
480
            }
481
        }
482
30965
    }
483
    /// Return the stream ID for the stream that this msg corresponds to, if any.
484
5060
    pub fn stream_id(&self) -> Option<StreamId> {
485
5060
        match &self.internal {
486
4840
            UnparsedRelayMsgInternal::V0(body) => StreamId::new(u16::from_be_bytes(
487
4840
                body[STREAM_ID_OFFSET_V0..STREAM_ID_OFFSET_V0 + 2]
488
4840
                    .try_into()
489
4840
                    .expect("two-byte slice was not two bytes long!?"),
490
4840
            )),
491
220
            UnparsedRelayMsgInternal::V1(body) => {
492
220
                match self.cmd().expects_streamid(Some(RelayCellFormat::V1)) {
493
110
                    StreamIdReq::WantNone => None,
494
                    StreamIdReq::Unrecognized | StreamIdReq::Any => None,
495
110
                    StreamIdReq::WantSome => StreamId::new(u16::from_be_bytes(
496
110
                        body[STREAM_ID_OFFSET_V1..STREAM_ID_OFFSET_V1 + 2]
497
110
                            .try_into()
498
110
                            .expect("two-byte slice was not two bytes long!?"),
499
110
                    )),
500
                }
501
            }
502
        }
503
5060
    }
504
    /// Return the "length" field of the cell.
505
    ///
506
    /// This is the size of the cell data (the "data" field), not the size of the cell.
507
    /// No bounds checking or validation is performed.
508
330
    pub fn data_len(&self) -> u16 {
509
330
        let bytes: [u8; 2] = match &self.internal {
510
110
            UnparsedRelayMsgInternal::V0(body) => &body[LENGTH_OFFSET_V0..LENGTH_OFFSET_V0 + 2],
511
220
            UnparsedRelayMsgInternal::V1(body) => &body[LENGTH_OFFSET_V1..LENGTH_OFFSET_V1 + 2],
512
        }
513
330
        .try_into()
514
330
        .expect("two-byte slice was not two bytes long!?");
515
330
        u16::from_be_bytes(bytes)
516
330
    }
517
    /// Decode this unparsed cell into a given cell type.
518
2896
    pub fn decode<M: RelayMsg>(self) -> Result<RelayMsgOuter<M>> {
519
2896
        match self.internal {
520
2876
            UnparsedRelayMsgInternal::V0(body) => {
521
2876
                let mut reader = Reader::from_slice(body.as_ref());
522
2876
                RelayMsgOuter::decode_v0_from_reader(&mut reader)
523
            }
524
20
            UnparsedRelayMsgInternal::V1(body) => {
525
20
                let mut reader = Reader::from_slice(body.as_ref());
526
20
                RelayMsgOuter::decode_v1_from_reader(&mut reader)
527
            }
528
        }
529
2896
    }
530
}
531

            
532
/// A decoded and parsed relay message of unrestricted type,
533
/// with an accompanying optional Stream ID.
534
pub type AnyRelayMsgOuter = RelayMsgOuter<msg::AnyRelayMsg>;
535

            
536
/// A deprecated name for AnyRelayMsgOuter.
537
#[deprecated(note = "Use AnyRelayMsgOuter instead.")]
538
pub type AnyRelayCell = AnyRelayMsgOuter;
539

            
540
/// Trait implemented by anything that can serve as a relay message.
541
///
542
/// Typically, this will be [`RelayMsg`] (to represent an unrestricted relay
543
/// message), or a restricted subset of `RelayMsg`.
544
pub trait RelayMsg {
545
    /// Return the stream command associated with this message.
546
    fn cmd(&self) -> RelayCmd;
547
    /// Encode the body of this message, not including command or length
548
    fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()>;
549
    /// Extract the body of a message with command `cmd` from reader `r`.
550
    fn decode_from_reader(cmd: RelayCmd, r: &mut Reader<'_>) -> Result<Self>
551
    where
552
        Self: Sized;
553
}
554

            
555
/// A decoded and parsed relay message, along with an optional Stream ID.
556
///
557
/// This type represents a message that can be sent along a
558
/// circuit, along with the ID for an associated stream that the
559
/// message is meant for.
560
///
561
/// NOTE: This name is a placeholder; we intend to replace it once we have
562
/// standardized our vocabulary in this area.
563
#[derive(Debug)]
564
pub struct RelayMsgOuter<M> {
565
    /// The stream ID for the stream that this cell corresponds to.
566
    streamid: Option<StreamId>,
567
    /// The relay message for this cell.
568
    msg: M,
569
}
570

            
571
/// A deprecated name for RelayMsgOuter.
572
#[deprecated(note = "Use RelayMsgOuter instead.")]
573
pub type RelayCell<M> = RelayMsgOuter<M>;
574

            
575
impl<M: RelayMsg> RelayMsgOuter<M> {
576
    /// Construct a new relay cell.
577
3130
    pub fn new(streamid: Option<StreamId>, msg: M) -> Self {
578
3130
        RelayMsgOuter { streamid, msg }
579
3130
    }
580
    /// Consume this cell and return its components.
581
2650
    pub fn into_streamid_and_msg(self) -> (Option<StreamId>, M) {
582
2650
        (self.streamid, self.msg)
583
2650
    }
584
    /// Return the command for this cell.
585
5804
    pub fn cmd(&self) -> RelayCmd {
586
5804
        self.msg.cmd()
587
5804
    }
588
    /// Return the stream ID for the stream that this cell corresponds to.
589
2912
    pub fn stream_id(&self) -> Option<StreamId> {
590
2912
        self.streamid
591
2912
    }
592
    /// Return the underlying message for this cell.
593
2746
    pub fn msg(&self) -> &M {
594
2746
        &self.msg
595
2746
    }
596
    /// Consume this cell and return the underlying message.
597
148
    pub fn into_msg(self) -> M {
598
148
        self.msg
599
148
    }
600
    /// Consume this relay message and encode it as a 509-byte padded cell
601
    /// body.
602
    //
603
    // TODO prop340: This API won't work for packed or fragmented messages.
604
3138
    pub fn encode<R: Rng + CryptoRng>(
605
3138
        self,
606
3138
        format: RelayCellFormat,
607
3138
        rng: &mut R,
608
3138
    ) -> crate::Result<BoxedCellBody> {
609
        /// We skip this much space before adding any random padding to the
610
        /// end of the cell
611
        const MIN_SPACE_BEFORE_PADDING: usize = 4;
612

            
613
3138
        let (mut body, enc_len) = match format {
614
3126
            RelayCellFormat::V0 => self.encode_to_cell_v0()?,
615
12
            RelayCellFormat::V1 => self.encode_to_cell_v1()?,
616
        };
617
3138
        debug_assert!(enc_len <= CELL_DATA_LEN);
618
3138
        if enc_len < CELL_DATA_LEN - MIN_SPACE_BEFORE_PADDING {
619
426
            rng.fill_bytes(&mut body[enc_len + MIN_SPACE_BEFORE_PADDING..]);
620
2728
        }
621

            
622
3138
        Ok(body)
623
3138
    }
624

            
625
    /// Consume a relay cell and return its contents, encoded for use
626
    /// in a RELAY or RELAY_EARLY cell.
627
3126
    fn encode_to_cell_v0(self) -> EncodeResult<(BoxedCellBody, usize)> {
628
        // NOTE: This implementation is a bit optimized, since it happens to
629
        // literally every relay cell that we produce.
630

            
631
        // TODO -NM: Add a specialized implementation for making a DATA cell from
632
        // a body?
633

            
634
        /// The position of the length field within a relay cell.
635
        const LEN_POS: usize = 9;
636
        /// The position of the body a relay cell.
637
        const BODY_POS: usize = 11;
638

            
639
3126
        let body = BodyWrapper(Box::new([0_u8; 509]));
640
3126

            
641
3126
        let mut w = crate::slicewriter::SliceWriter::new(body);
642
3126
        w.write_u8(self.msg.cmd().into());
643
3126
        w.write_u16(0); // "Recognized"
644
3126
        w.assert_offset_is(STREAM_ID_OFFSET_V0);
645
3126
        w.write_u16(StreamId::get_or_zero(self.streamid));
646
3126
        w.write_u32(0); // Digest
647
3126
                        // (It would be simpler to use NestedWriter at this point, but it uses an internal Vec that we are trying to avoid.)
648
3126
        w.assert_offset_is(LEN_POS);
649
3126
        w.write_u16(0); // Length.
650
3126
        w.assert_offset_is(BODY_POS);
651
3126
        self.msg.encode_onto(&mut w)?; // body
652
3126
        let (mut body, written) = w.try_unwrap().map_err(|_| {
653
            EncodeError::Bug(internal!(
654
                "Encoding of relay message was too long to fit into a cell!"
655
            ))
656
3126
        })?;
657
3126
        let payload_len = written - BODY_POS;
658
3126
        debug_assert!(payload_len < u16::MAX as usize);
659
3126
        *(<&mut [u8; 2]>::try_from(&mut body.0[LEN_POS..LEN_POS + 2])
660
3126
            .expect("Two-byte slice was not two bytes long!?")) =
661
3126
            (payload_len as u16).to_be_bytes();
662
3126
        Ok((body.0, written))
663
3126
    }
664

            
665
    /// Consume a relay cell and return its contents, encoded for use
666
    /// in a RELAY or RELAY_EARLY cell.
667
12
    fn encode_to_cell_v1(self) -> EncodeResult<(BoxedCellBody, usize)> {
668
        // NOTE: This implementation is a bit optimized, since it happens to
669
        // literally every relay cell that we produce.
670
        // TODO -NM: Add a specialized implementation for making a DATA cell from
671
        // a body?
672

            
673
        /// Position of the length field within the cell.
674
        const LEN_POS_V1: usize = 16 + 1; // Skipping tag, command.
675

            
676
12
        let cmd = self.msg.cmd();
677
12
        let body = BodyWrapper(Box::new([0_u8; 509]));
678
12
        let mut w = crate::slicewriter::SliceWriter::new(body);
679
12
        w.advance(16); // Tag: 16 bytes
680
12
        w.write_u8(cmd.get()); // Command: 1 byte.
681
12
        w.assert_offset_is(LEN_POS_V1);
682
12
        w.advance(2); //  Length: 2 bytes.
683
12
        let mut body_pos = 16 + 1 + 2;
684
12
        match (
685
12
            cmd.expects_streamid(Some(RelayCellFormat::V1)),
686
12
            self.streamid,
687
        ) {
688
8
            (StreamIdReq::WantNone, None) => {}
689
4
            (StreamIdReq::WantSome, Some(id)) => {
690
4
                w.write_u16(id.into());
691
4
                body_pos += 2;
692
4
            }
693
            (_, id) => {
694
                return Err(EncodeError::Bug(internal!(
695
                    "Tried to encode invalid stream ID {id:?} for {cmd}"
696
                )))
697
            }
698
        }
699
12
        w.assert_offset_is(body_pos);
700
12

            
701
12
        self.msg.encode_onto(&mut w)?; // body
702
12
        let (mut body, written) = w.try_unwrap().map_err(|_| {
703
            EncodeError::Bug(internal!(
704
                "Encoding of relay message was too long to fit into a cell!"
705
            ))
706
12
        })?;
707
12
        let payload_len = written - body_pos;
708
12
        debug_assert!(payload_len < u16::MAX as usize);
709
12
        *(<&mut [u8; 2]>::try_from(&mut body.0[LEN_POS_V1..LEN_POS_V1 + 2])
710
12
            .expect("Two-byte slice was not two bytes long!?")) =
711
12
            (payload_len as u16).to_be_bytes();
712
12
        Ok((body.0, written))
713
12
    }
714

            
715
    /// Parse a RELAY or RELAY_EARLY cell body into a RelayMsgOuter.
716
    /// Requires that the cryptographic checks on the message have already been
717
    /// performed
718
    ///
719
    /// Fails if the cell doesn't contain exactly one message.
720
    ///
721
    /// Non-test code should generally use `RelayCellDecoder` instead.
722
    // Ideally we'd make this `#[cfg(test)]`, but then we wouldn't be able
723
    // to use it in integration tests.
724
    // https://github.com/rust-lang/rust/issues/84629
725
    #[allow(clippy::needless_pass_by_value)] // TODO this will go away soon.
726
2684
    pub fn decode_singleton(version: RelayCellFormat, body: BoxedCellBody) -> Result<Self> {
727
2684
        let unparsed_msg = UnparsedRelayMsg::from_singleton_body(version, body)?;
728
2684
        unparsed_msg.decode()
729
2684
    }
730
    /// Parse a `RelayCellFormat::V0` RELAY or RELAY_EARLY cell body into a
731
    /// RelayMsgOuter from a reader.
732
    ///
733
    /// Requires that the cryptographic checks on the message have already been
734
    /// performed
735
2876
    fn decode_v0_from_reader(r: &mut Reader<'_>) -> Result<Self> {
736
2876
        let cmd = r.take_u8()?.into();
737
2876
        r.advance(2)?; // "recognized"
738
2876
        let streamid = StreamId::new(r.take_u16()?);
739
2876
        r.advance(4)?; // digest
740
2876
        let len = r.take_u16()? as usize;
741
2876
        if r.remaining() < len {
742
2
            return Err(Error::InvalidMessage(
743
2
                "Insufficient data in relay cell".into(),
744
2
            ));
745
2874
        }
746
2874
        r.truncate(len);
747
2874
        let msg = M::decode_from_reader(cmd, r)?;
748
2866
        Ok(Self { streamid, msg })
749
2876
    }
750

            
751
    /// Parse a `RelayCellFormat::V1` RELAY or RELAY_EARLY cell body into a
752
    /// RelayMsgOuter from a reader.
753
    ///
754
    /// Requires that the cryptographic checks on the message have already been
755
    /// performed.
756
20
    fn decode_v1_from_reader(r: &mut Reader<'_>) -> Result<Self> {
757
20
        r.advance(16)?; // Tag
758
20
        let cmd: RelayCmd = r.take_u8()?.into();
759
20
        let len = r.take_u16()?.into();
760
20
        let streamid = match cmd.expects_streamid(Some(RelayCellFormat::V1)) {
761
            // If no stream ID is expected, then the body begins immediately.
762
8
            StreamIdReq::WantNone => None,
763
            // In this case, a stream ID _is_ expected.
764
            //
765
            // (If it happens to be zero, we will reject the message,
766
            // since zero is never a stream ID.)
767
10
            StreamIdReq::WantSome => Some(StreamId::new(r.take_u16()?).ok_or_else(|| {
768
2
                Error::InvalidMessage(
769
2
                    format!("Zero-valued stream ID with relay command {cmd}").into(),
770
2
                )
771
10
            })?),
772
            // We treat an unrecognized command as having no stream ID.
773
            //
774
            // (Note: This command is truly unrecognized, and not one that we could parse
775
            // differently under other circumstances.)
776
            //
777
            // Note that this enables a destructive fingerprinting opportunity,
778
            // where an attacker can learn whether we have a version of Arti that recognizes this
779
            // command, at the expense of our killing this circuit immediately if they are wrong.
780
            // This is not a very bad attack.
781
            //
782
            // Note that StreamIdReq::Any should be impossible here, since we're using the V1
783
            // format.
784
            StreamIdReq::Unrecognized | StreamIdReq::Any => {
785
2
                return Err(Error::InvalidMessage(
786
2
                    format!("Unrecognized relay command {cmd}").into(),
787
2
                ))
788
            }
789
        };
790
16
        if r.remaining() < len {
791
            //
792
2
            return Err(Error::InvalidMessage(
793
2
                "Insufficient data in relay cell".into(),
794
2
            ));
795
14
        }
796
14
        r.truncate(len);
797
14
        let msg = M::decode_from_reader(cmd, r)?;
798
14
        Ok(Self { streamid, msg })
799
20
    }
800
}
801

            
802
/// Wrap a BoxedCellBody and implement AsMut<[u8]>, so we can use it with `SliceWriter`.
803
struct BodyWrapper(BoxedCellBody);
804
impl AsMut<[u8]> for BodyWrapper {
805
1076460
    fn as_mut(&mut self) -> &mut [u8] {
806
1076460
        self.0.as_mut()
807
1076460
    }
808
}