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