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

            
3
use crate::chancell::{RawCellBody, CELL_DATA_LEN};
4
use tor_bytes::{Error, Result};
5
use tor_bytes::{Reader, Writer};
6
use tor_error::internal;
7

            
8
use arrayref::array_mut_ref;
9
use caret::caret_int;
10
use rand::{CryptoRng, Rng};
11

            
12
pub mod msg;
13

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

            
48
        /// HS: establish an introduction point.
49
        ESTABLISH_INTRO = 32,
50
        /// HS: establish a rendezvous point.
51
        ESTABLISH_RENDEZVOUS = 33,
52
        /// HS: send introduction (client to introduction point)
53
        INTRODUCE1 = 34,
54
        /// HS: send introduction (introduction point to service)
55
        INTRODUCE2 = 35,
56
        /// HS: connect rendezvous point (service to rendezvous point)
57
        RENDEZVOUS1 = 36,
58
        /// HS: connect rendezvous point (rendezvous point to client)
59
        RENDEZVOUS2 = 37,
60
        /// HS: Response to ESTABLISH_INTRO
61
        INTRO_ESTABLISHED = 38,
62
        /// HS: Response to ESTABLISH_RENDEZVOUS
63
        RENDEZVOUS_ESTABLISHED = 39,
64
        /// HS: Response to INTRODUCE1 from introduction point to client
65
        INTRODUCE_ACK = 40,
66

            
67
        /// Padding: declare what kind of padding we want
68
        PADDING_NEGOTIATE = 41,
69
        /// Padding: reply to a PADDING_NEGOTIATE
70
        PADDING_NEGOTIATED = 42,
71
    }
72
}
73

            
74
/// Possible requirements on stream IDs for a relay command.
75
enum StreamIdReq {
76
    /// Can only be used with a stream ID of 0
77
    WantZero,
78
    /// Can only be used with a stream ID that isn't 0
79
    WantNonZero,
80
    /// Can be used with any stream ID
81
    Any,
82
}
83

            
84
impl RelayCmd {
85
    /// Check whether this command requires a certain kind of
86
    /// StreamId, and return a corresponding StreamIdReq.
87
1144
    fn expects_streamid(self) -> StreamIdReq {
88
1144
        match self {
89
            RelayCmd::BEGIN
90
            | RelayCmd::DATA
91
            | RelayCmd::END
92
            | RelayCmd::CONNECTED
93
            | RelayCmd::RESOLVE
94
            | RelayCmd::RESOLVED
95
484
            | RelayCmd::BEGIN_DIR => StreamIdReq::WantNonZero,
96
            RelayCmd::EXTEND
97
            | RelayCmd::EXTENDED
98
            | RelayCmd::TRUNCATE
99
            | RelayCmd::TRUNCATED
100
            | RelayCmd::DROP
101
            | RelayCmd::EXTEND2
102
            | RelayCmd::EXTENDED2
103
            | RelayCmd::ESTABLISH_INTRO
104
            | RelayCmd::ESTABLISH_RENDEZVOUS
105
            | RelayCmd::INTRODUCE1
106
            | RelayCmd::INTRODUCE2
107
            | RelayCmd::RENDEZVOUS1
108
            | RelayCmd::RENDEZVOUS2
109
            | RelayCmd::INTRO_ESTABLISHED
110
            | RelayCmd::RENDEZVOUS_ESTABLISHED
111
396
            | RelayCmd::INTRODUCE_ACK => StreamIdReq::WantZero,
112
264
            RelayCmd::SENDME => StreamIdReq::Any,
113
            _ => StreamIdReq::Any,
114
        }
115
1144
    }
116
    /// Return true if this command is one that accepts the particular
117
    /// stream ID `id`
118
1144
    pub fn accepts_streamid_val(self, id: StreamId) -> bool {
119
1144
        match (self.expects_streamid(), id.is_zero()) {
120
22
            (StreamIdReq::WantNonZero, true) => false,
121
22
            (StreamIdReq::WantZero, false) => false,
122
1100
            (_, _) => true,
123
        }
124
1144
    }
125
}
126

            
127
/// Identify a single stream on a circuit.
128
///
129
/// These identifiers are local to each hop on a circuit
130
5038
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
131
pub struct StreamId(u16);
132

            
133
impl From<u16> for StreamId {
134
7106
    fn from(v: u16) -> StreamId {
135
7106
        StreamId(v)
136
7106
    }
137
}
138

            
139
impl From<StreamId> for u16 {
140
44
    fn from(id: StreamId) -> u16 {
141
44
        id.0
142
44
    }
143
}
144

            
145
impl std::fmt::Display for StreamId {
146
44
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
147
44
        self.0.fmt(f)
148
44
    }
149
}
150

            
151
impl StreamId {
152
    /// Return true if this is the zero StreamId.
153
    ///
154
    /// A zero-valid circuit ID denotes a relay message that is not related to
155
    /// any particular stream, but which applies to the circuit as a whole.
156
58388
    pub fn is_zero(&self) -> bool {
157
58388
        self.0 == 0
158
58388
    }
159
}
160

            
161
/// A decoded and parsed relay cell.
162
///
163
/// Each relay cell represents a message that can be sent along a
164
/// circuit, along with the ID for an associated stream that the
165
/// message is meant for.
166
44
#[derive(Debug)]
167
pub struct RelayCell {
168
    /// The stream ID for the stream that this cell corresponds to.
169
    streamid: StreamId,
170
    /// The relay message for this cell.
171
    msg: msg::RelayMsg,
172
}
173

            
174
impl RelayCell {
175
    /// Construct a new relay cell.
176
54978
    pub fn new(streamid: StreamId, msg: msg::RelayMsg) -> Self {
177
54978
        RelayCell { streamid, msg }
178
54978
    }
179
    /// Consume this cell and return its components.
180
54406
    pub fn into_streamid_and_msg(self) -> (StreamId, msg::RelayMsg) {
181
54406
        (self.streamid, self.msg)
182
54406
    }
183
    /// Return the command for this cell.
184
22
    pub fn cmd(&self) -> RelayCmd {
185
22
        self.msg.cmd()
186
22
    }
187
    /// Return the stream ID for the stream that this cell corresponds to.
188
53834
    pub fn stream_id(&self) -> StreamId {
189
53834
        self.streamid
190
53834
    }
191
    /// Return the underlying message for this cell.
192
55132
    pub fn msg(&self) -> &msg::RelayMsg {
193
55132
        &self.msg
194
55132
    }
195
    /// Consume this relay message and encode it as a 509-byte padded cell
196
    /// body.
197
2498
    pub fn encode<R: Rng + CryptoRng>(self, rng: &mut R) -> crate::Result<RawCellBody> {
198
2498
        /// We skip this much space before adding any random padding to the
199
2498
        /// end of the cell
200
2498
        const MIN_SPACE_BEFORE_PADDING: usize = 4;
201
2498

            
202
2498
        // TODO: This implementation is inefficient; it copies too much.
203
2498
        let encoded = self.encode_to_vec();
204
2498
        let enc_len = encoded.len();
205
2498
        if enc_len > CELL_DATA_LEN {
206
            return Err(crate::Error::Internal(internal!(
207
                "too many bytes in relay cell"
208
            )));
209
2498
        }
210
2498
        let mut raw = [0_u8; CELL_DATA_LEN];
211
2498
        raw[0..enc_len].copy_from_slice(&encoded);
212
2498

            
213
2498
        if enc_len < CELL_DATA_LEN - MIN_SPACE_BEFORE_PADDING {
214
98
            rng.fill_bytes(&mut raw[enc_len + MIN_SPACE_BEFORE_PADDING..]);
215
2402
        }
216

            
217
2498
        Ok(raw)
218
2498
    }
219

            
220
    /// Consume a relay cell and return its contents, encoded for use
221
    /// in a RELAY or RELAY_EARLY cell
222
    ///
223
    /// TODO: not the best interface, as this requires copying into a cell.
224
54956
    fn encode_to_vec(self) -> Vec<u8> {
225
54956
        let mut w = Vec::new();
226
54956
        w.write_u8(self.msg.cmd().into());
227
54956
        w.write_u16(0); // "Recognized"
228
54956
        w.write_u16(self.streamid.0);
229
54956
        w.write_u32(0); // Digest
230
54956
        let len_pos = w.len();
231
54956
        w.write_u16(0); // Length.
232
54956
        let body_pos = w.len();
233
54956
        self.msg.encode_onto(&mut w);
234
54956
        assert!(w.len() >= body_pos); // nothing was removed
235
54956
        let payload_len = w.len() - body_pos;
236
54956
        assert!(payload_len <= std::u16::MAX as usize);
237
54956
        *(array_mut_ref![w, len_pos, 2]) = (payload_len as u16).to_be_bytes();
238
54956
        w
239
54956
    }
240
    /// Parse a RELAY or RELAY_EARLY cell body into a RelayCell.
241
    ///
242
    /// Requires that the cryptographic checks on the message have already been
243
    /// performed
244
54626
    pub fn decode(body: RawCellBody) -> Result<Self> {
245
54626
        let mut reader = Reader::from_slice(body.as_ref());
246
54626
        RelayCell::decode_from_reader(&mut reader)
247
54626
    }
248
    /// Parse a RELAY or RELAY_EARLY cell body into a RelayCell from a reader.
249
    ///
250
    /// Requires that the cryptographic checks on the message have already been
251
    /// performed
252
54626
    pub fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
253
54626
        let cmd = r.take_u8()?.into();
254
54626
        r.advance(2)?; // "recognized"
255
54626
        let streamid = StreamId(r.take_u16()?);
256
54626
        r.advance(4)?; // digest
257
54626
        let len = r.take_u16()? as usize;
258
54626
        if r.remaining() < len {
259
22
            return Err(Error::BadMessage("Insufficient data in relay cell"));
260
54604
        }
261
54604
        r.truncate(len);
262
54604
        let msg = msg::RelayMsg::decode_from_reader(cmd, r)?;
263
54604
        Ok(RelayCell { streamid, msg })
264
54626
    }
265
}