182 lines
5.9 KiB
Rust
182 lines
5.9 KiB
Rust
//! 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<u32> for CircId {
|
|
fn from(item: u32) -> Self {
|
|
Self(item)
|
|
}
|
|
}
|
|
impl From<CircId> 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)
|
|
}
|
|
}
|