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}