//! Messages sent over Tor channels //! //! A 'channel' is a direct connection between a tor client and a //! relay, or between two relays. Current channels all use TLS. //! //! This module implements the [ChanCell] type, which is the encoding for //! data sent over a channel. It also encodes and decodes various //! channel messages, which are the types of data conveyed over a //! channel. pub mod codec; pub mod msg; use caret::caret_int; /// The amount of data sent in a fixed-length cell. /// /// Historically, this was set at 509 bytes so that cells would be /// 512 bytes long once commands and circuit IDs were added. But now /// circuit IDs are longer, so cells are 514 bytes. pub const CELL_DATA_LEN: usize = 509; /// A cell body considered as a raw array of bytes pub type RawCellBody = [u8; CELL_DATA_LEN]; /// Channel-local identifier for a circuit. /// /// A circuit ID can be 2 or 4 bytes long; on modern versions of the Tor /// protocol, it's 4 bytes long. #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct CircId(u32); impl From for CircId { fn from(item: u32) -> Self { Self(item) } } impl From for u32 { fn from(id: CircId) -> u32 { id.0 } } impl std::fmt::Display for CircId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { self.0.fmt(f) } } impl CircId { /// Return true if this is the zero CircId. /// /// A zero-valid circuit ID denotes a cell that is not related to /// any particular circuit, but which applies to the channel as a whole. pub fn is_zero(&self) -> bool { self.0 == 0 } } caret_int! { /// A ChanCmd is the type of a channel cell. The value of the ChanCmd /// indicates the meaning of the cell, and (possibly) its length. pub struct ChanCmd(u8) { /// A fixed-length cell that will be dropped. PADDING = 0, /// Create a new circuit (obsolete format) CREATE = 1, /// Finish circuit-creation handshake (obsolete format) CREATED = 2, /// Relay cell, transmitted over a circuit. RELAY = 3, /// Destroy a circuit DESTROY = 4, /// Create a new circuit (no public-key) CREATE_FAST = 5, /// Finish a circuit-creation handshake (no public-key) CREATED_FAST = 6, // note gap in numbering: 7 is grouped with the variable-length cells /// Finish a channel handshake with time and address information NETINFO = 8, /// Relay cell, transmitted over a circuit. Limited. RELAY_EARLY = 9, /// Create a new circuit (current format) CREATE2 = 10, /// Finish a circuit-creation handshake (current format) CREATED2 = 11, /// Adjust channel-padding settings PADDING_NEGOTIATE = 12, /// Variable-length cell, despite its number: negotiate versions VERSIONS = 7, /// Variable-length channel-padding cell VPADDING = 128, /// Provide additional certificates beyond those given in the TLS /// handshake CERTS = 129, /// Challenge material used in relay-to-relay handshake. AUTH_CHALLENGE = 130, /// Response material used in relay-to-relay handshake. AUTHENTICATE = 131, /// Indicates client permission to use relay. Not currently used. AUTHORIZE = 132, } } /// Possible requirements on circuit IDs for a channel command. enum CircIdReq { /// indicates a command that only takes a zero-valued circuit ID WantZero, /// indicates a command that only takes a nonzero-valued circuit ID WantNonZero, /// indicates a command that can take any circuit ID Any, } impl ChanCmd { /// Return true if this command is for a cell using the the /// variable-length format. pub fn is_var_cell(self) -> bool { // Version 1 of the channel protocol had no variable-length // cells, but that's obsolete. In version 2, only the VERSIONS // cell was variable-length. self == ChanCmd::VERSIONS || self.0 >= 128_u8 } /// Return what kind of circuit ID this command expects. fn allows_circid(self) -> CircIdReq { match self { ChanCmd::PADDING | ChanCmd::NETINFO | ChanCmd::PADDING_NEGOTIATE | ChanCmd::VERSIONS | ChanCmd::VPADDING | ChanCmd::CERTS | ChanCmd::AUTH_CHALLENGE | ChanCmd::AUTHENTICATE => CircIdReq::WantZero, ChanCmd::CREATE | ChanCmd::CREATED | ChanCmd::RELAY | ChanCmd::DESTROY | ChanCmd::CREATE_FAST | ChanCmd::CREATED_FAST | ChanCmd::RELAY_EARLY | ChanCmd::CREATE2 | ChanCmd::CREATED2 => CircIdReq::WantNonZero, _ => CircIdReq::Any, } } /// Return true if this command is one that accepts the particular /// circuit ID `id`. pub fn accepts_circid_val(self, id: CircId) -> bool { match (self.allows_circid(), id.is_zero()) { (CircIdReq::WantNonZero, true) => false, (CircIdReq::WantZero, false) => false, (_, _) => true, } } } /// A decoded channel cell, to be sent or received on a channel. #[derive(Debug)] pub struct ChanCell { /// Circuit ID associated with this cell circid: CircId, /// Underlying message in this cell msg: msg::ChanMsg, } impl ChanCell { /// Construct a new channel cell. pub fn new(circid: CircId, msg: msg::ChanMsg) -> Self { ChanCell { circid, msg } } /// Return the circuit ID for this cell. pub fn circid(&self) -> CircId { self.circid } /// Return a reference to the underlying message of this cell. pub fn msg(&self) -> &msg::ChanMsg { &self.msg } /// Consume this cell and return its components. pub fn into_circid_and_msg(self) -> (CircId, msg::ChanMsg) { (self.circid, self.msg) } }