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 tor_bytes::{EncodeError, EncodeResult, Error, Result};
7
use tor_bytes::{Reader, Writer};
8
use tor_error::internal;
9

            
10
use caret::caret_int;
11
use rand::{CryptoRng, Rng};
12

            
13
pub mod extend;
14
#[cfg(feature = "hs")]
15
pub mod hs;
16
pub mod msg;
17
#[cfg(feature = "experimental-udp")]
18
pub mod udp;
19

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

            
54
        /// NOTE: UDP command are reserved but only used with experimental-udp feature
55

            
56
        /// UDP: Start of a stream
57
        CONNECT_UDP = 16,
58
        /// UDP: Acknowledge a CONNECT_UDP. Stream is open.
59
        CONNECTED_UDP = 17,
60
        /// UDP: Data on a UDP stream.
61
        DATAGRAM = 18,
62

            
63
        /// HS: establish an introduction point.
64
        ESTABLISH_INTRO = 32,
65
        /// HS: establish a rendezvous point.
66
        ESTABLISH_RENDEZVOUS = 33,
67
        /// HS: send introduction (client to introduction point)
68
        INTRODUCE1 = 34,
69
        /// HS: send introduction (introduction point to service)
70
        INTRODUCE2 = 35,
71
        /// HS: connect rendezvous point (service to rendezvous point)
72
        RENDEZVOUS1 = 36,
73
        /// HS: connect rendezvous point (rendezvous point to client)
74
        RENDEZVOUS2 = 37,
75
        /// HS: Response to ESTABLISH_INTRO
76
        INTRO_ESTABLISHED = 38,
77
        /// HS: Response to ESTABLISH_RENDEZVOUS
78
        RENDEZVOUS_ESTABLISHED = 39,
79
        /// HS: Response to INTRODUCE1 from introduction point to client
80
        INTRODUCE_ACK = 40,
81

            
82
        /// Padding: declare what kind of padding we want
83
        PADDING_NEGOTIATE = 41,
84
        /// Padding: reply to a PADDING_NEGOTIATE
85
        PADDING_NEGOTIATED = 42,
86
    }
87
}
88

            
89
/// Possible requirements on stream IDs for a relay command.
90
enum StreamIdReq {
91
    /// Can only be used with a stream ID of 0
92
    WantNone,
93
    /// Can only be used with a stream ID that isn't 0
94
    WantSome,
95
    /// Can be used with any stream ID
96
    Any,
97
}
98

            
99
impl RelayCmd {
100
    /// Check whether this command requires a certain kind of
101
    /// StreamId, and return a corresponding StreamIdReq.
102
4516
    fn expects_streamid(self) -> StreamIdReq {
103
4516
        match self {
104
            RelayCmd::BEGIN
105
            | RelayCmd::DATA
106
            | RelayCmd::END
107
            | RelayCmd::CONNECTED
108
            | RelayCmd::RESOLVE
109
            | RelayCmd::RESOLVED
110
2834
            | RelayCmd::BEGIN_DIR => StreamIdReq::WantSome,
111
            #[cfg(feature = "experimental-udp")]
112
            RelayCmd::CONNECT_UDP | RelayCmd::CONNECTED_UDP | RelayCmd::DATAGRAM => {
113
                StreamIdReq::WantSome
114
            }
115
            RelayCmd::EXTEND
116
            | RelayCmd::EXTENDED
117
            | RelayCmd::TRUNCATE
118
            | RelayCmd::TRUNCATED
119
            | RelayCmd::DROP
120
            | RelayCmd::EXTEND2
121
            | RelayCmd::EXTENDED2
122
            | RelayCmd::ESTABLISH_INTRO
123
            | RelayCmd::ESTABLISH_RENDEZVOUS
124
            | RelayCmd::INTRODUCE1
125
            | RelayCmd::INTRODUCE2
126
            | RelayCmd::RENDEZVOUS1
127
            | RelayCmd::RENDEZVOUS2
128
            | RelayCmd::INTRO_ESTABLISHED
129
            | RelayCmd::RENDEZVOUS_ESTABLISHED
130
1118
            | RelayCmd::INTRODUCE_ACK => StreamIdReq::WantNone,
131
564
            RelayCmd::SENDME => StreamIdReq::Any,
132
            _ => StreamIdReq::Any,
133
        }
134
4516
    }
135
    /// Return true if this command is one that accepts the particular
136
    /// stream ID `id`
137
4516
    pub fn accepts_streamid_val(self, id: Option<StreamId>) -> bool {
138
4516
        match self.expects_streamid() {
139
1118
            StreamIdReq::WantNone => id.is_none(),
140
2834
            StreamIdReq::WantSome => id.is_some(),
141
564
            StreamIdReq::Any => true,
142
        }
143
4516
    }
144
}
145

            
146
/// Identify a single stream on a circuit.
147
///
148
/// These identifiers are local to each hop on a circuit.
149
/// This can't be zero; if you need something that can be zero in the protocol,
150
/// use `Option<StreamId>`.
151
13842
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
152
pub struct StreamId(NonZeroU16);
153

            
154
impl From<NonZeroU16> for StreamId {
155
21846
    fn from(id: NonZeroU16) -> Self {
156
21846
        Self(id)
157
21846
    }
158
}
159

            
160
impl From<StreamId> for NonZeroU16 {
161
12774
    fn from(id: StreamId) -> NonZeroU16 {
162
12774
        id.0
163
12774
    }
164
}
165

            
166
impl From<StreamId> for u16 {
167
    fn from(id: StreamId) -> u16 {
168
        id.0.get()
169
    }
170
}
171

            
172
impl std::fmt::Display for StreamId {
173
47
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
174
47
        self.0.fmt(f)
175
47
    }
176
}
177

            
178
impl StreamId {
179
    /// Creates a `StreamId` for non-zero `stream_id`.
180
    ///
181
    /// Returns `None` when `stream_id` is zero. Messages with a zero/None stream ID
182
    /// apply to the circuit as a whole instead of a particular stream.
183
126814
    pub fn new(stream_id: u16) -> Option<Self> {
184
126814
        NonZeroU16::new(stream_id).map(Self)
185
126814
    }
186

            
187
    /// Convenience function to convert to a `u16`; `None` is mapped to 0.
188
121277
    pub fn get_or_zero(stream_id: Option<Self>) -> u16 {
189
121277
        match stream_id {
190
118326
            Some(stream_id) => stream_id.0.get(),
191
2951
            None => 0,
192
        }
193
121277
    }
194
}
195

            
196
/// A relay cell that has not yet been fully parsed, but where we have access to
197
/// the command and stream ID, for dispatching purposes.
198
//
199
// TODO prop340: Further discussion is necessary about standardizing names for
200
// all of the pieces of our cells.
201
#[derive(Clone, Debug)]
202
pub struct UnparsedRelayCell {
203
    /// The body of the cell.
204
    body: BoxedCellBody,
205
    // NOTE: we could also have a separate command and stream ID field here, but
206
    // we expect to be working with a TON of these, so we will be mildly
207
    // over-optimized and just peek into the body.
208
    //
209
    // It *is* a bit ugly to have to encode so much knowledge about the format in
210
    // different functions here, but that information shouldn't leak out of this module.
211
}
212
/// Position of the stream ID within the cell body.
213
const STREAM_ID_OFFSET: usize = 3;
214

            
215
impl UnparsedRelayCell {
216
    /// Wrap a BoxedCellBody as an UnparsedRelayCell.
217
6020
    pub fn from_body(body: BoxedCellBody) -> Self {
218
6020
        Self { body }
219
6020
    }
220
    /// Return the command for this cell.
221
25753
    pub fn cmd(&self) -> RelayCmd {
222
25753
        /// Position of the command within the cell body.
223
25753
        const CMD_OFFSET: usize = 0;
224
25753
        self.body[CMD_OFFSET].into()
225
25753
    }
226
    /// Return the stream ID for the stream that this cell corresponds to, if any.
227
4328
    pub fn stream_id(&self) -> Option<StreamId> {
228
4328
        StreamId::new(u16::from_be_bytes(
229
4328
            self.body[STREAM_ID_OFFSET..STREAM_ID_OFFSET + 2]
230
4328
                .try_into()
231
4328
                .expect("two-byte slice was not two bytes long!?"),
232
4328
        ))
233
4328
    }
234
    /// Decode this unparsed cell into a given cell type.
235
942
    pub fn decode<M: RelayMsg>(self) -> Result<RelayMsgOuter<M>> {
236
942
        RelayMsgOuter::decode(self.body)
237
942
    }
238
}
239

            
240
/// A decoded and parsed relay message of unrestricted type,
241
/// with an accompanying optional Stream ID.
242
pub type AnyRelayMsgOuter = RelayMsgOuter<msg::AnyRelayMsg>;
243

            
244
/// A deprecated name for AnyRelayMsgOuter.
245
#[deprecated(note = "Use AnyRelayMsgOuter instead.")]
246
pub type AnyRelayCell = AnyRelayMsgOuter;
247

            
248
/// Trait implemented by anything that can serve as a relay message.
249
///
250
/// Typically, this will be [`RelayMsg`] (to represent an unrestricted relay
251
/// message), or a restricted subset of `RelayMsg`.
252
pub trait RelayMsg {
253
    /// Return the stream command associated with this message.
254
    fn cmd(&self) -> RelayCmd;
255
    /// Encode the body of this message, not including command or length
256
    fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()>;
257
    /// Extract the body of a message with command `cmd` from reader `r`.
258
    fn decode_from_reader(cmd: RelayCmd, r: &mut Reader<'_>) -> Result<Self>
259
    where
260
        Self: Sized;
261
}
262

            
263
/// A decoded and parsed relay message, along with an optional Stream ID.
264
///
265
/// This type represents a message that can be sent along a
266
/// circuit, along with the ID for an associated stream that the
267
/// message is meant for.
268
///
269
/// NOTE: This name is a placeholder; we intend to replace it once we have
270
/// standardized our vocabulary in this area.
271
8
#[derive(Debug)]
272
pub struct RelayMsgOuter<M> {
273
    /// The stream ID for the stream that this cell corresponds to.
274
    streamid: Option<StreamId>,
275
    /// The relay message for this cell.
276
    msg: M,
277
}
278

            
279
/// A deprecated name for RelayMsgOuter.
280
#[deprecated(note = "Use RelayMsgOuter instead.")]
281
pub type RelayCell<M> = RelayMsgOuter<M>;
282

            
283
impl<M: RelayMsg> RelayMsgOuter<M> {
284
    /// Construct a new relay cell.
285
5396
    pub fn new(streamid: Option<StreamId>, msg: M) -> Self {
286
5396
        RelayMsgOuter { streamid, msg }
287
5396
    }
288
    /// Consume this cell and return its components.
289
4850
    pub fn into_streamid_and_msg(self) -> (Option<StreamId>, M) {
290
4850
        (self.streamid, self.msg)
291
4850
    }
292
    /// Return the command for this cell.
293
5186
    pub fn cmd(&self) -> RelayCmd {
294
5186
        self.msg.cmd()
295
5186
    }
296
    /// Return the stream ID for the stream that this cell corresponds to.
297
5184
    pub fn stream_id(&self) -> Option<StreamId> {
298
5184
        self.streamid
299
5184
    }
300
    /// Return the underlying message for this cell.
301
26
    pub fn msg(&self) -> &M {
302
26
        &self.msg
303
26
    }
304
    /// Consume this cell and return the underlying message.
305
884
    pub fn into_msg(self) -> M {
306
884
        self.msg
307
884
    }
308
    /// Consume this relay message and encode it as a 509-byte padded cell
309
    /// body.
310
5398
    pub fn encode<R: Rng + CryptoRng>(self, rng: &mut R) -> crate::Result<BoxedCellBody> {
311
        /// We skip this much space before adding any random padding to the
312
        /// end of the cell
313
        const MIN_SPACE_BEFORE_PADDING: usize = 4;
314

            
315
5398
        let (mut body, enc_len) = self.encode_to_cell()?;
316
5398
        debug_assert!(enc_len <= CELL_DATA_LEN);
317
5398
        if enc_len < CELL_DATA_LEN - MIN_SPACE_BEFORE_PADDING {
318
598
            rng.fill_bytes(&mut body[enc_len + MIN_SPACE_BEFORE_PADDING..]);
319
5056
        }
320

            
321
5398
        Ok(body)
322
5398
    }
323

            
324
    /// Consume a relay cell and return its contents, encoded for use
325
    /// in a RELAY or RELAY_EARLY cell.
326
5398
    fn encode_to_cell(self) -> EncodeResult<(BoxedCellBody, usize)> {
327
5398
        // NOTE: This implementation is a bit optimized, since it happens to
328
5398
        // literally every relay cell that we produce.
329
5398

            
330
5398
        // TODO -NM: Add a specialized implementation for making a DATA cell from
331
5398
        // a body?
332
5398

            
333
5398
        /// Wrap a BoxedCellBody and implement AsMut<[u8]>
334
5398
        struct BodyWrapper(BoxedCellBody);
335
5398
        impl AsMut<[u8]> for BodyWrapper {
336
1486159
            fn as_mut(&mut self) -> &mut [u8] {
337
1486159
                self.0.as_mut()
338
1486159
            }
339
5398
        }
340
5398
        /// The position of the length field within a relay cell.
341
5398
        const LEN_POS: usize = 9;
342
5398
        /// The position of the body a relay cell.
343
5398
        const BODY_POS: usize = 11;
344
5398

            
345
5398
        let body = BodyWrapper(Box::new([0_u8; 509]));
346
5398

            
347
5398
        let mut w = crate::slicewriter::SliceWriter::new(body);
348
5398
        w.write_u8(self.msg.cmd().into());
349
5398
        w.write_u16(0); // "Recognized"
350
        debug_assert_eq!(
351
5398
            w.offset().expect("Overflowed a cell with just the header!"),
352
            STREAM_ID_OFFSET
353
        );
354
5398
        w.write_u16(StreamId::get_or_zero(self.streamid));
355
5398
        w.write_u32(0); // Digest
356
                        // (It would be simpler to use NestedWriter at this point, but it uses an internal Vec that we are trying to avoid.)
357
        debug_assert_eq!(
358
5398
            w.offset().expect("Overflowed a cell with just the header!"),
359
            LEN_POS
360
        );
361
5398
        w.write_u16(0); // Length.
362
        debug_assert_eq!(
363
5398
            w.offset().expect("Overflowed a cell with just the header!"),
364
            BODY_POS
365
        );
366
5398
        self.msg.encode_onto(&mut w)?; // body
367
5398
        let (mut body, written) = w.try_unwrap().map_err(|_| {
368
            EncodeError::Bug(internal!(
369
                "Encoding of relay message was too long to fit into a cell!"
370
            ))
371
5398
        })?;
372
5398
        let payload_len = written - BODY_POS;
373
5398
        debug_assert!(payload_len < std::u16::MAX as usize);
374
5398
        *(<&mut [u8; 2]>::try_from(&mut body.0[LEN_POS..LEN_POS + 2])
375
5398
            .expect("Two-byte slice was not two bytes long!?")) =
376
5398
            (payload_len as u16).to_be_bytes();
377
5398
        Ok((body.0, written))
378
5398
    }
379

            
380
    /// Parse a RELAY or RELAY_EARLY cell body into a RelayMsgOuter.
381
    ///
382
    /// Requires that the cryptographic checks on the message have already been
383
    /// performed
384
    #[allow(clippy::needless_pass_by_value)] // TODO this will go away soon.
385
5820
    pub fn decode(body: BoxedCellBody) -> Result<Self> {
386
5820
        let mut reader = Reader::from_slice(body.as_ref());
387
5820
        Self::decode_from_reader(&mut reader)
388
5820
    }
389
    /// Parse a RELAY or RELAY_EARLY cell body into a RelayMsgOuter from a reader.
390
    ///
391
    /// Requires that the cryptographic checks on the message have already been
392
    /// performed
393
5820
    pub fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
394
5820
        let cmd = r.take_u8()?.into();
395
5820
        r.advance(2)?; // "recognized"
396
5820
        let streamid = StreamId::new(r.take_u16()?);
397
5820
        r.advance(4)?; // digest
398
5820
        let len = r.take_u16()? as usize;
399
5820
        if r.remaining() < len {
400
2
            return Err(Error::InvalidMessage(
401
2
                "Insufficient data in relay cell".into(),
402
2
            ));
403
5818
        }
404
5818
        r.truncate(len);
405
5818
        let msg = M::decode_from_reader(cmd, r)?;
406
5810
        Ok(Self { streamid, msg })
407
5820
    }
408
}