Skip to main content

tor_proto/channel/
msg.rs

1//! This contains restricted message sets namespaced by link protocol version.
2//!
3//! In other words, each protocol version define sets of possible messages depending on the channel
4//! type as in client or relay and initiator or responder.
5//!
6//! This module also defines [`MessageFilter`] which can be used to filter messages based on
7//! specific details of the message such as direction, command, channel type and channel stage.
8
9use bytes::{Bytes, BytesMut};
10use tor_cell::chancell::{AnyChanCell, ChanCell, ChanMsg, codec, msg::AnyChanMsg};
11
12use crate::{Error, channel::ChannelType};
13
14/// Subprotocol LINK version 4.
15///
16/// Increases circuit ID width to 4 bytes.
17pub(super) mod linkv4 {
18    use bytes::{Bytes, BytesMut};
19    use tor_cell::{
20        chancell::{AnyChanCell, codec},
21        restricted_msg,
22    };
23
24    use super::MessageStage;
25    use crate::{
26        Error,
27        channel::{
28            ChannelType,
29            msg::{decode_as_any, encode_as_any},
30        },
31    };
32
33    restricted_msg! {
34        /// Handshake messages of a relay that initiates a connection. They are sent by the
35        /// initiator and thus received by the responder.
36        #[derive(Clone, Debug)]
37        pub(super) enum HandshakeRelayInitiatorMsg: ChanMsg {
38            Authenticate,
39            Certs,
40            Netinfo,
41            Vpadding,
42        }
43    }
44
45    restricted_msg! {
46        /// Handshake messages of a relay that responds to a connection. They are received by the
47        /// initiator and thus sent by the responder.
48        #[derive(Clone, Debug)]
49        pub(super) enum HandshakeRelayResponderMsg: ChanMsg {
50            AuthChallenge,
51            Certs,
52            Netinfo,
53            Vpadding,
54        }
55    }
56
57    restricted_msg! {
58        /// Handshake messages of a client that initiates a connection to a relay.
59        ///
60        /// The Versions message is not in this set as it is a special case as the very first cell
61        /// being negotiated in order to learn the link protocol version.
62        ///
63        /// This MUST be a subset of HandshakeRelayResponderMsg because the relay responder doesn't
64        /// know what the other side will send depending if it wants to authenticate or not.
65        #[derive(Clone, Debug)]
66        pub(super) enum HandshakeClientInitiatorMsg: ChanMsg {
67            Netinfo,
68            Vpadding,
69        }
70    }
71
72    // From this point on, the C is "Client" and the R is "Relay" and the name indicate the
73    // direction of messages. For example, C2R means client -> (to) relay.
74
75    restricted_msg! {
76        /// A channel message that we allow to be sent from a Client to a Relay on
77        /// an open channel.
78        #[derive(Clone, Debug)]
79        pub(super) enum OpenChanMsgC2R: ChanMsg {
80            // No Create*, it is obsolete (TAP).
81            Create2,
82            CreateFast,
83            Destroy,
84            Padding,
85            Vpadding,
86            // No PaddingNegotiate, it is v5+ only.
87            Relay,
88            RelayEarly,
89        }
90    }
91
92    restricted_msg! {
93        /// A channel message that we allow to be sent from a Relay to a Client on
94        /// an open channel.
95        ///
96        /// (An Open channel here is one on which we have received a NETINFO cell.)
97        #[derive(Clone, Debug)]
98        pub(super) enum OpenChanMsgR2C : ChanMsg {
99            // No Create*, we are not a client and it is obsolete (TAP).
100            // No Created*, it is obsolete (TAP).
101            CreatedFast,
102            Created2,
103            Relay,
104            // No RelayEarly, only for client.
105            Destroy,
106            Padding,
107            Vpadding,
108        }
109    }
110
111    restricted_msg! {
112        /// A channel message that we allow to be sent (bidirectionally) from a Relay to a Relay on
113        /// an open channel.
114        #[derive(Clone, Debug)]
115        pub(super) enum OpenChanMsgR2R : ChanMsg {
116            // No Vpadding, only sent during handshake.
117            // No Create/Created, it is obsolete (TAP).
118            CreateFast,
119            CreatedFast,
120            Create2,
121            Created2,
122            Destroy,
123            Padding,
124            Vpadding,
125            Relay,
126            RelayEarly,
127            // No PaddingNegotiate, only client sends this.
128            // No Versions, Certs, AuthChallenge, Authenticate, Netinfo: they are for handshakes.
129            // No Authorize: it is reserved, but unused.
130        }
131    }
132
133    /// Decode cell using the given channel type, message stage, codec and byte source.
134    ///
135    /// Returns both the cell and the bytes that the cell were decoded from.
136    pub(super) fn decode_cell(
137        chan_type: ChannelType,
138        stage: &MessageStage,
139        codec: &mut codec::ChannelCodec,
140        src: &mut BytesMut,
141    ) -> Result<Option<(AnyChanCell, Bytes)>, Error> {
142        use ChannelType::*;
143        use MessageStage::*;
144
145        let decode_fn = match (chan_type, stage) {
146            (ClientInitiator, Handshake) => decode_as_any::<HandshakeRelayResponderMsg>,
147            (ClientInitiator, Open) => decode_as_any::<OpenChanMsgR2C>,
148            (RelayInitiator, Handshake) => decode_as_any::<HandshakeRelayResponderMsg>,
149            (RelayInitiator, Open) => decode_as_any::<OpenChanMsgR2R>,
150            (RelayResponder { authenticated: _ }, Handshake) => {
151                // We don't know if the other side is a client or relay.
152                // However, the `HandshakeRelayInitiatorMsg` message set
153                // is a superset of the `HandshakeClientInitiatorMsg` message set
154                // and so we cover any client-sent messages as well.
155                decode_as_any::<HandshakeRelayInitiatorMsg>
156            }
157            (RelayResponder { authenticated }, Open) => match authenticated {
158                false => decode_as_any::<OpenChanMsgC2R>,
159                true => decode_as_any::<OpenChanMsgR2R>,
160            },
161        };
162
163        decode_fn(stage, codec, src)
164    }
165
166    /// Encode a given cell which can contains any type of messages. It is filtered through its
167    /// restricted message set at encoding time.
168    ///
169    /// Return an error if encoding fails or if cell is disallowed.
170    pub(super) fn encode_cell(
171        chan_type: ChannelType,
172        stage: &MessageStage,
173        cell: AnyChanCell,
174        codec: &mut codec::ChannelCodec,
175        dst: &mut BytesMut,
176    ) -> Result<(), Error> {
177        use ChannelType::*;
178        use MessageStage::*;
179
180        let encode_fn = match (chan_type, stage) {
181            (ClientInitiator, Handshake) => encode_as_any::<HandshakeClientInitiatorMsg>,
182            (ClientInitiator, Open) => encode_as_any::<OpenChanMsgC2R>,
183            (RelayInitiator, Handshake) => encode_as_any::<HandshakeRelayInitiatorMsg>,
184            (RelayInitiator, Open) => encode_as_any::<OpenChanMsgR2R>,
185            (RelayResponder { authenticated: _ }, Handshake) => {
186                encode_as_any::<HandshakeRelayResponderMsg>
187            }
188            (RelayResponder { authenticated }, Open) => match authenticated {
189                false => encode_as_any::<OpenChanMsgR2C>,
190                true => encode_as_any::<OpenChanMsgR2R>,
191            },
192        };
193
194        encode_fn(stage, cell, codec, dst)
195    }
196}
197
198/// Subprotocol LINK version 5.
199///
200/// Adds support for padding and negotiation.
201pub(super) mod linkv5 {
202    use bytes::{Bytes, BytesMut};
203    use tor_cell::{
204        chancell::{AnyChanCell, codec},
205        restricted_msg,
206    };
207
208    use super::MessageStage;
209    use crate::{
210        Error,
211        channel::{
212            ChannelType,
213            msg::{decode_as_any, encode_as_any},
214        },
215    };
216
217    restricted_msg! {
218        /// Handshake messages of a relay that initiates a connection. They are sent by the
219        /// initiator and thus received by the responder.
220        #[derive(Clone,Debug)]
221        pub(super) enum HandshakeRelayInitiatorMsg: ChanMsg {
222            Authenticate,
223            Certs,
224            Netinfo,
225            Vpadding,
226        }
227    }
228
229    restricted_msg! {
230        /// Handshake messages of a relay that responds to a connection. They are received by the
231        /// initiator and thus sent by the responder.
232        #[derive(Clone,Debug)]
233        pub(super) enum HandshakeRelayResponderMsg: ChanMsg {
234            AuthChallenge,
235            Certs,
236            Netinfo,
237            Vpadding,
238        }
239    }
240
241    restricted_msg! {
242        /// Handshake messages of a client that initiates a connection to a relay.
243        ///
244        /// The Versions message is not in this set as it is a special case as the very first cell
245        /// being negotiated in order to learn the link protocol version.
246        #[derive(Clone,Debug)]
247        pub(super) enum HandshakeClientInitiatorMsg: ChanMsg {
248            Netinfo,
249            Vpadding,
250        }
251    }
252
253    // From this point on, the C is "Client" and the R is "Relay" and the name indicate the
254    // direction of messages. For example, C2R means client -> (to) relay.
255
256    restricted_msg! {
257        /// A channel message that we allow to be sent from a Client to a Relay on
258        /// an open channel.
259        #[derive(Clone, Debug)]
260        pub(super) enum OpenChanMsgC2R: ChanMsg {
261            // No Create*, it is obsolete (TAP).
262            Create2,
263            CreateFast,
264            Destroy,
265            Padding,
266            PaddingNegotiate,
267            Vpadding,
268            Relay,
269            RelayEarly,
270        }
271    }
272
273    restricted_msg! {
274        /// A channel message that we allow to be sent from a Relay to a Client on
275        /// an open channel.
276        ///
277        /// (An Open channel here is one on which we have received a NETINFO cell.)
278        #[derive(Clone, Debug)]
279        pub(super) enum OpenChanMsgR2C : ChanMsg {
280            // No Create/d*, only clients and it is obsolete (TAP).
281            CreatedFast,
282            Created2,
283            Destroy,
284            Padding,
285            Vpadding,
286            Relay,
287            // No PaddingNegotiate, only clients.
288            // No Versions, Certs, AuthChallenge, Authenticate: they are for handshakes.
289            // No Authorize: it is reserved, but unused.
290        }
291    }
292
293    restricted_msg! {
294        /// A channel message that we allow to be sent (bidirectionally) from a Relay to a Relay on
295        /// an open channel.
296        #[derive(Clone, Debug)]
297        pub(super) enum OpenChanMsgR2R : ChanMsg {
298            // No Create/Created, it is obsolete (TAP).
299            CreateFast,
300            CreatedFast,
301            Create2,
302            Created2,
303            Destroy,
304            Padding,
305            Vpadding,
306            // No Vpadding, only sent during handshake.
307            Relay,
308            RelayEarly,
309            // No PaddingNegotiate, only client sends this.
310            // No Versions, Certs, AuthChallenge, Authenticate, Netinfo: they are for handshakes.
311            // No Authorize: it is reserved, but unused.
312        }
313    }
314
315    /// Decode cell using the given channel type, message stage, codec and byte source.
316    ///
317    /// Returns both the cell and the bytes that the cell were decoded from.
318    pub(super) fn decode_cell(
319        chan_type: ChannelType,
320        stage: &MessageStage,
321        codec: &mut codec::ChannelCodec,
322        src: &mut BytesMut,
323    ) -> Result<Option<(AnyChanCell, Bytes)>, Error> {
324        use ChannelType::*;
325        use MessageStage::*;
326
327        let decode_fn = match (chan_type, stage) {
328            (ClientInitiator, Handshake) => decode_as_any::<HandshakeRelayResponderMsg>,
329            (ClientInitiator, Open) => decode_as_any::<OpenChanMsgR2C>,
330            (RelayInitiator, Handshake) => decode_as_any::<HandshakeRelayResponderMsg>,
331            (RelayInitiator, Open) => decode_as_any::<OpenChanMsgR2R>,
332            (RelayResponder { authenticated: _ }, Handshake) => {
333                // We don't know if the other side is a client or relay.
334                // However, the `HandshakeRelayInitiatorMsg` message set
335                // is a superset of the `HandshakeClientInitiatorMsg` message set
336                // and so we cover any client-sent messages as well.
337                decode_as_any::<HandshakeRelayInitiatorMsg>
338            }
339            (RelayResponder { authenticated }, Open) => match authenticated {
340                false => decode_as_any::<OpenChanMsgC2R>,
341                true => decode_as_any::<OpenChanMsgR2R>,
342            },
343        };
344
345        decode_fn(stage, codec, src)
346    }
347
348    /// Encode a given cell which can contains any type of messages. It is filtered through its
349    /// restricted message set at encoding time.
350    ///
351    /// Return an error if encoding fails or if cell is disallowed.
352    pub(super) fn encode_cell(
353        chan_type: ChannelType,
354        stage: &MessageStage,
355        cell: AnyChanCell,
356        codec: &mut codec::ChannelCodec,
357        dst: &mut BytesMut,
358    ) -> Result<(), Error> {
359        use ChannelType::*;
360        use MessageStage::*;
361
362        let encode_fn = match (chan_type, stage) {
363            (ClientInitiator, Handshake) => encode_as_any::<HandshakeClientInitiatorMsg>,
364            (ClientInitiator, Open) => encode_as_any::<OpenChanMsgC2R>,
365            (RelayInitiator, Handshake) => encode_as_any::<HandshakeRelayInitiatorMsg>,
366            (RelayInitiator, Open) => encode_as_any::<OpenChanMsgR2R>,
367            (RelayResponder { authenticated: _ }, Handshake) => {
368                encode_as_any::<HandshakeRelayResponderMsg>
369            }
370            (RelayResponder { authenticated }, Open) => match authenticated {
371                false => encode_as_any::<OpenChanMsgR2C>,
372                true => encode_as_any::<OpenChanMsgR2R>,
373            },
374        };
375
376        encode_fn(stage, cell, codec, dst)
377    }
378}
379
380/// Helper function to decode a cell within a restricted msg set into an AnyChanCell.
381///
382/// The given stage is used to know which error to return.
383///
384/// Returns both the cell and the bytes that the cell were decoded from.
385fn decode_as_any<R>(
386    stage: &MessageStage,
387    codec: &mut codec::ChannelCodec,
388    src: &mut BytesMut,
389) -> Result<Option<(AnyChanCell, Bytes)>, Error>
390where
391    R: Into<AnyChanMsg> + ChanMsg,
392{
393    codec
394        .decode_cell::<R>(src)
395        .map(|opt| {
396            opt.map(|(cell, cell_bytes)| {
397                let (circid, msg) = cell.into_circid_and_msg();
398                (ChanCell::new(circid, msg.into()), cell_bytes)
399            })
400        })
401        .map_err(|e| stage.to_err(format!("Decoding cell error: {e}")))
402}
403
404/// Helper function to encode an AnyChanCell cell that is within a restricted msg set R.
405///
406/// The given stage is used to know which error to return.
407fn encode_as_any<R>(
408    stage: &MessageStage,
409    cell: AnyChanCell,
410    codec: &mut codec::ChannelCodec,
411    dst: &mut BytesMut,
412) -> Result<(), Error>
413where
414    R: ChanMsg + TryFrom<AnyChanMsg, Error = AnyChanMsg>,
415{
416    let (circ_id, any_msg) = cell.into_circid_and_msg();
417
418    match R::try_from(any_msg) {
419        Ok(rmsg) => {
420            let rcell: ChanCell<R> = ChanCell::new(circ_id, rmsg);
421            codec
422                .write_cell(rcell, dst)
423                .map_err(|e| stage.to_err(format!("Encoding cell error: {e}")))
424        }
425        Err(m) => Err(stage.to_err(format!("Disallowed cell command {}", m.cmd(),))),
426    }
427}
428
429/// Channel protocol version negotiated.
430#[derive(Copy, Clone, Debug)]
431pub(super) enum LinkVersion {
432    /// Version 4 that need to use linkv4:: messages.
433    V4,
434    /// Version 5 that need to use linkv5:: messages.
435    V5,
436}
437
438impl LinkVersion {
439    /// Return the value of this link version as a u16. Useful for lower level crates that require
440    /// the value for which we can't export this enum.
441    pub(super) fn value(&self) -> u16 {
442        match self {
443            Self::V4 => 4,
444            Self::V5 => 5,
445        }
446    }
447}
448
449impl TryFrom<u16> for LinkVersion {
450    type Error = Error;
451
452    fn try_from(value: u16) -> Result<Self, Self::Error> {
453        Ok(match value {
454            4 => Self::V4,
455            5 => Self::V5,
456            _ => {
457                return Err(Error::HandshakeProto(format!(
458                    "Unknown link version {value}"
459                )));
460            }
461        })
462    }
463}
464
465/// What stage a channel can be of a negotiation. This is used in order to learn which restricted
466/// message set we should be looking at.
467///
468/// Notice that we don't have the "New" stage and this is because we only learn the link protocol
469/// version once we enter the Handshake stage.
470pub(super) enum MessageStage {
471    /// Handshaking as in the channel is working to become open.
472    Handshake,
473    /// Open as the channel is now open.
474    Open,
475}
476
477impl MessageStage {
478    /// Return an error using the given message for the right stage.
479    ///
480    /// Very useful helper that just select the right error type for the stage.
481    fn to_err(&self, msg: String) -> Error {
482        match self {
483            Self::Handshake => Error::HandshakeProto(msg),
484            Self::Open => Error::ChanProto(msg),
485        }
486    }
487}
488
489/// A message filter object which is used to learn if a certain message is allowed or not on a
490/// channel.
491///
492/// It is pinned to a link protocol version, a channel type and a channel message stage.
493pub(super) struct MessageFilter {
494    /// For what link protocol version this filter applies for.
495    link_version: LinkVersion,
496    /// For which channel type this filter applies for.
497    channel_type: ChannelType,
498    /// At which stage this filter applies for.
499    stage: MessageStage,
500}
501
502impl MessageFilter {
503    /// Constructor
504    pub(super) fn new(
505        link_version: LinkVersion,
506        channel_type: ChannelType,
507        stage: MessageStage,
508    ) -> Self {
509        Self {
510            link_version,
511            channel_type,
512            stage,
513        }
514    }
515
516    /// Return the [`ChannelType`] of this filter.
517    pub(super) fn channel_type(&self) -> ChannelType {
518        self.channel_type
519    }
520
521    /// Return the [`ChannelType`] of this filter as a mutable.
522    pub(super) fn channel_type_mut(&mut self) -> &mut ChannelType {
523        &mut self.channel_type
524    }
525
526    /// Decode a cell from the given bytes for the right link version, channel type and message
527    /// stage using the codec given.
528    ///
529    /// Returns both the cell and the bytes that the cell were decoded from.
530    pub(super) fn decode_cell(
531        &self,
532        codec: &mut codec::ChannelCodec,
533        src: &mut BytesMut,
534    ) -> Result<Option<(AnyChanCell, Bytes)>, Error> {
535        match self.link_version {
536            LinkVersion::V4 => linkv4::decode_cell(self.channel_type, &self.stage, codec, src),
537            LinkVersion::V5 => linkv5::decode_cell(self.channel_type, &self.stage, codec, src),
538        }
539    }
540
541    /// Decode a cell from the given bytes for the right link version, channel type and message
542    /// stage using the codec given.
543    pub(super) fn encode_cell(
544        &self,
545        cell: AnyChanCell,
546        codec: &mut codec::ChannelCodec,
547        dst: &mut BytesMut,
548    ) -> Result<(), Error> {
549        match self.link_version {
550            LinkVersion::V4 => {
551                linkv4::encode_cell(self.channel_type, &self.stage, cell, codec, dst)
552            }
553            LinkVersion::V5 => {
554                linkv5::encode_cell(self.channel_type, &self.stage, cell, codec, dst)
555            }
556        }
557    }
558}