tor_cell/chancell.rs
1//! Messages sent over Tor channels
2//!
3//! A 'channel' is a direct connection between a tor client and a
4//! relay, or between two relays. Current channels all use TLS.
5//!
6//! This module implements the [ChanCell] type, which is the encoding for
7//! data sent over a channel. It also encodes and decodes various
8//! channel messages, which are the types of data conveyed over a
9//! channel.
10pub mod codec;
11pub mod msg;
12use std::num::NonZeroU32;
13
14use caret::caret_int;
15use derive_deftly::Deftly;
16use tor_memquota::{derive_deftly_template_HasMemoryCost, HasMemoryCostStructural};
17
18/// The amount of data sent in a fixed-length cell.
19///
20/// Historically, this was set at 509 bytes so that cells would be
21/// 512 bytes long once commands and circuit IDs were added. But since
22/// protocol version 4, circuit IDs are 2 bytes longer, so cells are
23/// now 514 bytes.
24pub const CELL_DATA_LEN: usize = 509;
25
26/// A cell body considered as a raw array of bytes
27pub type RawCellBody = [u8; CELL_DATA_LEN];
28
29/// A [`RawCellBody`] stored on the heap.
30///
31/// We use this often to avoid copying cell bodies around.
32pub type BoxedCellBody = Box<RawCellBody>;
33
34/// Channel-local identifier for a circuit.
35///
36/// A circuit ID can be 2 or 4 bytes long; since version 4 of the Tor
37/// protocol, it's 4 bytes long.
38///
39/// Cannot be zero. For an "optional" circuit ID, use `Option<CircId>`.
40#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
41pub struct CircId(NonZeroU32);
42
43impl From<NonZeroU32> for CircId {
44 fn from(item: NonZeroU32) -> Self {
45 Self(item)
46 }
47}
48impl From<CircId> for u32 {
49 fn from(id: CircId) -> u32 {
50 id.0.get()
51 }
52}
53impl std::fmt::Display for CircId {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
55 self.0.fmt(f)
56 }
57}
58impl CircId {
59 /// Creates a `CircId` for non-zero `val`.
60 ///
61 /// Returns `None` when `val` is zero. Messages with a zero/None circuit ID
62 /// apply to the channel as a whole.
63 pub fn new(val: u32) -> Option<Self> {
64 NonZeroU32::new(val).map(Self)
65 }
66
67 /// Convenience function to convert to a `u32`; `None` is mapped to 0.
68 pub fn get_or_zero(circ_id: Option<Self>) -> u32 {
69 match circ_id {
70 Some(circ_id) => circ_id.0.get(),
71 None => 0,
72 }
73 }
74}
75
76caret_int! {
77 /// A ChanCmd is the type of a channel cell. The value of the ChanCmd
78 /// indicates the meaning of the cell, and (possibly) its length.
79 #[derive(Deftly)]
80 #[derive_deftly(HasMemoryCost)]
81 pub struct ChanCmd(u8) {
82 /// A fixed-length cell that will be dropped.
83 PADDING = 0,
84 /// Create a new circuit (obsolete format)
85 CREATE = 1,
86 /// Finish circuit-creation handshake (obsolete format)
87 CREATED = 2,
88 /// Relay cell, transmitted over a circuit.
89 RELAY = 3,
90 /// Destroy a circuit
91 DESTROY = 4,
92 /// Create a new circuit (no public-key)
93 CREATE_FAST = 5,
94 /// Finish a circuit-creation handshake (no public-key)
95 CREATED_FAST = 6,
96 // note gap in numbering: 7 is grouped with the variable-length cells
97 /// Finish a channel handshake with time and address information
98 NETINFO = 8,
99 /// Relay cell, transmitted over a circuit. Limited.
100 RELAY_EARLY = 9,
101 /// Create a new circuit (current format)
102 CREATE2 = 10,
103 /// Finish a circuit-creation handshake (current format)
104 CREATED2 = 11,
105 /// Adjust channel-padding settings
106 PADDING_NEGOTIATE = 12,
107
108 /// Variable-length cell, despite its number: negotiate versions
109 VERSIONS = 7,
110 /// Variable-length channel-padding cell
111 VPADDING = 128,
112 /// Provide additional certificates beyond those given in the TLS
113 /// handshake
114 CERTS = 129,
115 /// Challenge material used in relay-to-relay handshake.
116 AUTH_CHALLENGE = 130,
117 /// Response material used in relay-to-relay handshake.
118 AUTHENTICATE = 131,
119 /// Indicates client permission to use relay. Not currently used.
120 AUTHORIZE = 132,
121 }
122}
123
124/// Possible requirements on circuit IDs for a channel command.
125enum CircIdReq {
126 /// indicates a command that only takes a zero-valued circuit ID
127 WantNone,
128 /// indicates a command that only takes a nonzero-valued circuit ID
129 WantSome,
130 /// indicates a command that can take any circuit ID
131 Any,
132}
133
134impl ChanCmd {
135 /// Return true if this command is for a cell using the
136 /// variable-length format.
137 pub fn is_var_cell(self) -> bool {
138 // Version 1 of the channel protocol had no variable-length
139 // cells, but that's obsolete. In version 2, only the VERSIONS
140 // cell was variable-length. Since version 3, all cells having
141 // a command value >= 128 are variable-length.
142 self == ChanCmd::VERSIONS || self.0 >= 128_u8
143 }
144 /// Return what kind of circuit ID this command expects.
145 fn allows_circid(self) -> CircIdReq {
146 match self {
147 ChanCmd::PADDING
148 | ChanCmd::NETINFO
149 | ChanCmd::PADDING_NEGOTIATE
150 | ChanCmd::VERSIONS
151 | ChanCmd::VPADDING
152 | ChanCmd::CERTS
153 | ChanCmd::AUTH_CHALLENGE
154 | ChanCmd::AUTHENTICATE => CircIdReq::WantNone,
155 ChanCmd::CREATE
156 | ChanCmd::CREATED
157 | ChanCmd::RELAY
158 | ChanCmd::DESTROY
159 | ChanCmd::CREATE_FAST
160 | ChanCmd::CREATED_FAST
161 | ChanCmd::RELAY_EARLY
162 | ChanCmd::CREATE2
163 | ChanCmd::CREATED2 => CircIdReq::WantSome,
164 _ => CircIdReq::Any,
165 }
166 }
167 /// Return true if this command is one that accepts the particular
168 /// circuit ID `id`.
169 pub fn accepts_circid_val(self, id: Option<CircId>) -> bool {
170 match self.allows_circid() {
171 CircIdReq::WantNone => id.is_none(),
172 CircIdReq::WantSome => id.is_some(),
173 CircIdReq::Any => true,
174 }
175 }
176}
177
178/// A decoded and parsed channel cell of unrestricted type.
179pub type AnyChanCell = ChanCell<msg::AnyChanMsg>;
180
181/// Trait implemented by anything that can serve as a channel message.
182///
183/// Typically, this will be [`AnyChanMsg`](msg::AnyChanMsg) (to represent an unrestricted relay
184/// message), or some restricted subset of those messages.
185pub trait ChanMsg {
186 /// Return the [`ChanCmd`] for this message.
187 fn cmd(&self) -> ChanCmd;
188 /// Write the body of this message (not including length or command).
189 fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()>;
190 /// Decode this message from a given reader, according to a specified
191 /// command value. The reader must be truncated to the exact length
192 /// of the body.
193 fn decode_from_reader(cmd: ChanCmd, r: &mut tor_bytes::Reader<'_>) -> tor_bytes::Result<Self>
194 where
195 Self: Sized;
196}
197
198/// A decoded channel cell, to be sent or received on a channel.
199#[derive(Debug, Deftly)]
200#[derive_deftly(HasMemoryCost)]
201#[deftly(has_memory_cost(bounds = "M: HasMemoryCostStructural"))]
202pub struct ChanCell<M> {
203 /// Circuit ID associated with this cell, if any.
204 #[deftly(has_memory_cost(copy))]
205 circid: Option<CircId>,
206 /// Underlying message in this cell
207 msg: M,
208}
209
210impl<M: ChanMsg> ChanCell<M> {
211 /// Construct a new channel cell.
212 pub fn new(circid: Option<CircId>, msg: M) -> Self {
213 ChanCell { circid, msg }
214 }
215 /// Return the circuit ID for this cell.
216 pub fn circid(&self) -> Option<CircId> {
217 self.circid
218 }
219 /// Return a reference to the underlying message of this cell.
220 pub fn msg(&self) -> &M {
221 &self.msg
222 }
223 /// Consume this cell and return its components.
224 pub fn into_circid_and_msg(self) -> (Option<CircId>, M) {
225 (self.circid, self.msg)
226 }
227}