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}