use std::num::NonZeroU16;
use crate::chancell::{BoxedCellBody, CELL_DATA_LEN};
use derive_deftly::Deftly;
use smallvec::{SmallVec, smallvec};
use tor_bytes::{EncodeError, EncodeResult, Error, Result};
use tor_bytes::{Reader, Writer};
use tor_error::internal;
use tor_memquota::derive_deftly_template_HasMemoryCost;
use caret::caret_int;
use rand::{CryptoRng, Rng};
#[cfg(feature = "conflux")]
pub mod conflux;
pub mod extend;
mod extlist;
pub mod flow_ctrl;
#[cfg(feature = "hs")]
pub mod hs;
pub mod msg;
#[cfg(feature = "experimental-udp")]
pub mod udp;
caret_int! {
#[derive(Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct RelayCmd(u8) {
BEGIN = 1,
DATA = 2,
END = 3,
CONNECTED = 4,
SENDME = 5,
EXTEND = 6,
EXTENDED = 7,
TRUNCATE = 8,
TRUNCATED = 9,
DROP = 10,
RESOLVE = 11,
RESOLVED = 12,
BEGIN_DIR = 13,
EXTEND2 = 14,
EXTENDED2 = 15,
CONNECT_UDP = 16,
CONNECTED_UDP = 17,
DATAGRAM = 18,
CONFLUX_LINK = 19,
CONFLUX_LINKED = 20,
CONFLUX_LINKED_ACK = 21,
CONFLUX_SWITCH = 22,
ESTABLISH_INTRO = 32,
ESTABLISH_RENDEZVOUS = 33,
INTRODUCE1 = 34,
INTRODUCE2 = 35,
RENDEZVOUS1 = 36,
RENDEZVOUS2 = 37,
INTRO_ESTABLISHED = 38,
RENDEZVOUS_ESTABLISHED = 39,
INTRODUCE_ACK = 40,
PADDING_NEGOTIATE = 41,
PADDING_NEGOTIATED = 42,
XOFF = 43,
XON = 44,
}
}
enum StreamIdReq {
WantNone,
WantSome,
Any,
Unrecognized,
}
impl RelayCmd {
fn expects_streamid(self, format: Option<RelayCellFormat>) -> StreamIdReq {
match self {
RelayCmd::BEGIN
| RelayCmd::DATA
| RelayCmd::END
| RelayCmd::CONNECTED
| RelayCmd::RESOLVE
| RelayCmd::RESOLVED
| RelayCmd::BEGIN_DIR
| RelayCmd::XOFF
| RelayCmd::XON => StreamIdReq::WantSome,
RelayCmd::CONNECT_UDP | RelayCmd::CONNECTED_UDP | RelayCmd::DATAGRAM => {
StreamIdReq::WantSome
}
RelayCmd::EXTEND
| RelayCmd::EXTENDED
| RelayCmd::TRUNCATE
| RelayCmd::TRUNCATED
| RelayCmd::DROP
| RelayCmd::EXTEND2
| RelayCmd::EXTENDED2
| RelayCmd::CONFLUX_LINK
| RelayCmd::CONFLUX_LINKED
| RelayCmd::CONFLUX_LINKED_ACK
| RelayCmd::CONFLUX_SWITCH
| RelayCmd::ESTABLISH_INTRO
| RelayCmd::ESTABLISH_RENDEZVOUS
| RelayCmd::INTRODUCE1
| RelayCmd::INTRODUCE2
| RelayCmd::RENDEZVOUS1
| RelayCmd::RENDEZVOUS2
| RelayCmd::INTRO_ESTABLISHED
| RelayCmd::RENDEZVOUS_ESTABLISHED
| RelayCmd::INTRODUCE_ACK => StreamIdReq::WantNone,
RelayCmd::SENDME => match format {
Some(RelayCellFormat::V1) => StreamIdReq::WantNone,
Some(RelayCellFormat::V0) => StreamIdReq::Any,
None => StreamIdReq::Any,
},
_ => StreamIdReq::Unrecognized,
}
}
pub fn accepts_streamid_val(self, id: Option<StreamId>) -> bool {
match self.expects_streamid(None) {
StreamIdReq::WantNone => id.is_none(),
StreamIdReq::WantSome => id.is_some(),
StreamIdReq::Any => true,
StreamIdReq::Unrecognized => true,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Hash, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct StreamId(NonZeroU16);
impl From<NonZeroU16> for StreamId {
fn from(id: NonZeroU16) -> Self {
Self(id)
}
}
impl From<StreamId> for NonZeroU16 {
fn from(id: StreamId) -> NonZeroU16 {
id.0
}
}
impl From<StreamId> for u16 {
fn from(id: StreamId) -> u16 {
id.0.get()
}
}
impl std::fmt::Display for StreamId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
self.0.fmt(f)
}
}
impl StreamId {
pub fn new(stream_id: u16) -> Option<Self> {
NonZeroU16::new(stream_id).map(Self)
}
pub fn get_or_zero(stream_id: Option<Self>) -> u16 {
match stream_id {
Some(stream_id) => stream_id.0.get(),
None => 0,
}
}
}
#[non_exhaustive]
#[derive(Copy, Clone, Debug)]
pub enum RelayCellFormat {
V0,
V1,
}
#[derive(Clone, Debug)]
enum RelayCellDecoderInternal {
V0,
V1,
}
#[derive(Clone, Debug)]
pub struct RelayCellDecoder {
internal: RelayCellDecoderInternal,
}
impl RelayCellDecoder {
pub fn new(version: RelayCellFormat) -> Self {
match version {
RelayCellFormat::V0 => Self {
internal: RelayCellDecoderInternal::V0,
},
RelayCellFormat::V1 => Self {
internal: RelayCellDecoderInternal::V1,
},
}
}
pub fn decode(&mut self, cell: BoxedCellBody) -> Result<RelayCellDecoderResult> {
let msg_internal = match &self.internal {
RelayCellDecoderInternal::V0 => UnparsedRelayMsgInternal::V0(cell),
RelayCellDecoderInternal::V1 => UnparsedRelayMsgInternal::V1(cell),
};
Ok(RelayCellDecoderResult {
msgs: smallvec![UnparsedRelayMsg {
internal: msg_internal
}],
incomplete: None,
})
}
pub fn incomplete_info(&self) -> Option<IncompleteRelayMsgInfo> {
match &self.internal {
RelayCellDecoderInternal::V0 | RelayCellDecoderInternal::V1 => None,
}
}
}
#[derive(Debug)]
pub struct RelayCellDecoderResult {
msgs: SmallVec<[UnparsedRelayMsg; 1]>,
incomplete: Option<IncompleteRelayMsgInfo>,
}
impl RelayCellDecoderResult {
pub fn cmds(&self) -> impl Iterator<Item = RelayCmd> + '_ {
let complete_msg_cmds = self.msgs.iter().map(|m| m.cmd());
let partial_msg_cmd = self.incomplete.as_ref().map(|c| c.cmd());
complete_msg_cmds.chain(partial_msg_cmd)
}
pub fn into_parts(
self,
) -> (
impl Iterator<Item = UnparsedRelayMsg>,
Option<IncompleteRelayMsgInfo>,
) {
(self.msgs.into_iter(), self.incomplete)
}
pub fn incomplete_info(&self) -> Option<IncompleteRelayMsgInfo> {
self.incomplete.clone()
}
pub fn is_padding(&self) -> bool {
self.msgs.iter().all(|m| m.cmd() == RelayCmd::DROP) &&
self.incomplete
.as_ref()
.is_none_or(|incomplete| incomplete.cmd() == RelayCmd::DROP)
}
}
#[derive(Clone, Debug)]
pub struct IncompleteRelayMsgInfo {
cmd: RelayCmd,
stream_id: Option<StreamId>,
total_msg_len: usize,
num_bytes_present: usize,
}
impl IncompleteRelayMsgInfo {
pub fn cmd(&self) -> RelayCmd {
self.cmd
}
pub fn stream_id(&self) -> Option<StreamId> {
self.stream_id
}
pub fn total_msg_len(&self) -> usize {
self.total_msg_len
}
pub fn num_bytes_present(&self) -> usize {
self.num_bytes_present
}
pub fn num_bytes_missing(&self) -> usize {
self.total_msg_len - self.num_bytes_present
}
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
enum UnparsedRelayMsgInternal {
V0(BoxedCellBody),
V1(BoxedCellBody),
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct UnparsedRelayMsg {
internal: UnparsedRelayMsgInternal,
}
const fn min(a: u16, b: u16, c: u16) -> u16 {
const fn min_2(a: u16, b: u16) -> u16 {
if a < b { a } else { b }
}
min_2(a, min_2(b, c))
}
const fn max(a: u16, b: u16, c: u16) -> u16 {
const fn max_2(a: u16, b: u16) -> u16 {
if a > b { a } else { b }
}
max_2(a, max_2(b, c))
}
const STREAM_ID_OFFSET_V0: usize = 3;
const STREAM_ID_OFFSET_V1: usize = 16 + 1 + 2;
const LENGTH_OFFSET_V0: usize = 1 + 2 + 2 + 4;
const LENGTH_OFFSET_V1: usize = 16 + 1;
const PAYLOAD_OFFSET_V0: usize = LENGTH_OFFSET_V0 + 2;
const PAYLOAD_OFFSET_V1_WITHOUT_STREAM_ID: usize = LENGTH_OFFSET_V1 + 2;
const PAYLOAD_OFFSET_V1_WITH_STREAM_ID: usize = LENGTH_OFFSET_V1 + 2 + 2;
const PAYLOAD_MAX_SIZE_V0: u16 = BODY_MAX_LEN_V0 - (PAYLOAD_OFFSET_V0 as u16);
const PAYLOAD_MAX_SIZE_V1_WITHOUT_STREAM_ID: u16 =
BODY_MAX_LEN_V1 - (PAYLOAD_OFFSET_V1_WITHOUT_STREAM_ID as u16);
const PAYLOAD_MAX_SIZE_V1_WITH_STREAM_ID: u16 =
BODY_MAX_LEN_V1 - (PAYLOAD_OFFSET_V1_WITH_STREAM_ID as u16);
const BODY_MAX_LEN_V0: u16 = 509;
const BODY_MAX_LEN_V1: u16 = 509;
pub const PAYLOAD_MAX_SIZE_ALL: u16 = min(
PAYLOAD_MAX_SIZE_V0,
PAYLOAD_MAX_SIZE_V1_WITH_STREAM_ID,
PAYLOAD_MAX_SIZE_V1_WITHOUT_STREAM_ID,
);
pub const PAYLOAD_MAX_SIZE_ANY: u16 = max(
PAYLOAD_MAX_SIZE_V0,
PAYLOAD_MAX_SIZE_V1_WITH_STREAM_ID,
PAYLOAD_MAX_SIZE_V1_WITHOUT_STREAM_ID,
);
impl UnparsedRelayMsg {
pub fn from_singleton_body(version: RelayCellFormat, body: BoxedCellBody) -> Result<Self> {
let mut decoder = RelayCellDecoder::new(version);
let res = decoder.decode(body)?;
let (mut msgs, incomplete) = res.into_parts();
let Some(msg) = msgs.next() else {
return Err(Error::MissingData);
};
if incomplete.is_some() {
return Err(Error::ExtraneousBytes);
}
if msgs.next().is_some() {
return Err(Error::ExtraneousBytes);
}
Ok(msg)
}
pub fn cmd(&self) -> RelayCmd {
match &self.internal {
UnparsedRelayMsgInternal::V0(body) => {
const CMD_OFFSET: usize = 0;
body[CMD_OFFSET].into()
}
UnparsedRelayMsgInternal::V1(body) => {
const CMD_OFFSET: usize = 16;
body[CMD_OFFSET].into()
}
}
}
pub fn stream_id(&self) -> Option<StreamId> {
match &self.internal {
UnparsedRelayMsgInternal::V0(body) => StreamId::new(u16::from_be_bytes(
body[STREAM_ID_OFFSET_V0..STREAM_ID_OFFSET_V0 + 2]
.try_into()
.expect("two-byte slice was not two bytes long!?"),
)),
UnparsedRelayMsgInternal::V1(body) => {
match self.cmd().expects_streamid(Some(RelayCellFormat::V1)) {
StreamIdReq::WantNone => None,
StreamIdReq::Unrecognized | StreamIdReq::Any => None,
StreamIdReq::WantSome => StreamId::new(u16::from_be_bytes(
body[STREAM_ID_OFFSET_V1..STREAM_ID_OFFSET_V1 + 2]
.try_into()
.expect("two-byte slice was not two bytes long!?"),
)),
}
}
}
}
pub fn data_len(&self) -> Result<u16> {
if self.cmd() != RelayCmd::DATA {
return Ok(0);
}
let bytes: [u8; 2] = match &self.internal {
UnparsedRelayMsgInternal::V0(body) => &body[LENGTH_OFFSET_V0..LENGTH_OFFSET_V0 + 2],
UnparsedRelayMsgInternal::V1(body) => &body[LENGTH_OFFSET_V1..LENGTH_OFFSET_V1 + 2],
}
.try_into()
.expect("two-byte slice was not two bytes long!?");
let len = u16::from_be_bytes(bytes);
let max = match &self.internal {
UnparsedRelayMsgInternal::V0(_body) => BODY_MAX_LEN_V0,
UnparsedRelayMsgInternal::V1(_body) => BODY_MAX_LEN_V1,
};
if len > max {
return Err(Error::BadLengthValue);
}
Ok(len)
}
pub fn decode<M: RelayMsg>(self) -> Result<RelayMsgOuter<M>> {
match self.internal {
UnparsedRelayMsgInternal::V0(body) => {
let mut reader = Reader::from_slice(body.as_ref());
RelayMsgOuter::decode_v0_from_reader(&mut reader)
}
UnparsedRelayMsgInternal::V1(body) => {
let mut reader = Reader::from_slice(body.as_ref());
RelayMsgOuter::decode_v1_from_reader(&mut reader)
}
}
}
}
pub type AnyRelayMsgOuter = RelayMsgOuter<msg::AnyRelayMsg>;
#[deprecated(note = "Use AnyRelayMsgOuter instead.")]
pub type AnyRelayCell = AnyRelayMsgOuter;
pub trait RelayMsg {
fn cmd(&self) -> RelayCmd;
fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()>;
fn decode_from_reader(cmd: RelayCmd, r: &mut Reader<'_>) -> Result<Self>
where
Self: Sized;
}
#[derive(Debug)]
pub struct RelayMsgOuter<M> {
streamid: Option<StreamId>,
msg: M,
}
#[deprecated(note = "Use RelayMsgOuter instead.")]
pub type RelayCell<M> = RelayMsgOuter<M>;
impl<M: RelayMsg> RelayMsgOuter<M> {
pub fn new(streamid: Option<StreamId>, msg: M) -> Self {
RelayMsgOuter { streamid, msg }
}
pub fn into_streamid_and_msg(self) -> (Option<StreamId>, M) {
(self.streamid, self.msg)
}
pub fn cmd(&self) -> RelayCmd {
self.msg.cmd()
}
pub fn stream_id(&self) -> Option<StreamId> {
self.streamid
}
pub fn msg(&self) -> &M {
&self.msg
}
pub fn into_msg(self) -> M {
self.msg
}
pub fn encode<R: Rng + CryptoRng>(
self,
format: RelayCellFormat,
rng: &mut R,
) -> crate::Result<BoxedCellBody> {
const MIN_SPACE_BEFORE_PADDING: usize = 4;
let (mut body, enc_len) = match format {
RelayCellFormat::V0 => self.encode_to_cell_v0()?,
RelayCellFormat::V1 => self.encode_to_cell_v1()?,
};
debug_assert!(enc_len <= CELL_DATA_LEN);
if enc_len < CELL_DATA_LEN - MIN_SPACE_BEFORE_PADDING {
rng.fill_bytes(&mut body[enc_len + MIN_SPACE_BEFORE_PADDING..]);
}
Ok(body)
}
fn encode_to_cell_v0(self) -> EncodeResult<(BoxedCellBody, usize)> {
const LEN_POS: usize = 9;
const BODY_POS: usize = 11;
let body = BodyWrapper(Box::new([0_u8; BODY_MAX_LEN_V0 as usize]));
let mut w = crate::slicewriter::SliceWriter::new(body);
w.write_u8(self.msg.cmd().into());
w.write_u16(0); w.assert_offset_is(STREAM_ID_OFFSET_V0);
w.write_u16(StreamId::get_or_zero(self.streamid));
w.write_u32(0); w.assert_offset_is(LEN_POS);
w.write_u16(0); w.assert_offset_is(BODY_POS);
self.msg.encode_onto(&mut w)?; let (mut body, written) = w.try_unwrap().map_err(|_| {
EncodeError::Bug(internal!(
"Encoding of relay message was too long to fit into a cell!"
))
})?;
let payload_len = written - BODY_POS;
debug_assert!(payload_len < u16::MAX as usize);
*(<&mut [u8; 2]>::try_from(&mut body.0[LEN_POS..LEN_POS + 2])
.expect("Two-byte slice was not two bytes long!?")) =
(payload_len as u16).to_be_bytes();
Ok((body.0, written))
}
fn encode_to_cell_v1(self) -> EncodeResult<(BoxedCellBody, usize)> {
const LEN_POS_V1: usize = 16 + 1;
let cmd = self.msg.cmd();
let body = BodyWrapper(Box::new([0_u8; BODY_MAX_LEN_V1 as usize]));
let mut w = crate::slicewriter::SliceWriter::new(body);
w.advance(16); w.write_u8(cmd.get()); w.assert_offset_is(LEN_POS_V1);
w.advance(2); let mut body_pos = 16 + 1 + 2;
match (
cmd.expects_streamid(Some(RelayCellFormat::V1)),
self.streamid,
) {
(StreamIdReq::WantNone, None) => {}
(StreamIdReq::WantSome, Some(id)) => {
w.write_u16(id.into());
body_pos += 2;
}
(_, id) => {
return Err(EncodeError::Bug(internal!(
"Tried to encode invalid stream ID {id:?} for {cmd}"
)));
}
}
w.assert_offset_is(body_pos);
self.msg.encode_onto(&mut w)?; let (mut body, written) = w.try_unwrap().map_err(|_| {
EncodeError::Bug(internal!(
"Encoding of relay message was too long to fit into a cell!"
))
})?;
let payload_len = written - body_pos;
debug_assert!(payload_len < u16::MAX as usize);
*(<&mut [u8; 2]>::try_from(&mut body.0[LEN_POS_V1..LEN_POS_V1 + 2])
.expect("Two-byte slice was not two bytes long!?")) =
(payload_len as u16).to_be_bytes();
Ok((body.0, written))
}
#[allow(clippy::needless_pass_by_value)] pub fn decode_singleton(version: RelayCellFormat, body: BoxedCellBody) -> Result<Self> {
let unparsed_msg = UnparsedRelayMsg::from_singleton_body(version, body)?;
unparsed_msg.decode()
}
fn decode_v0_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let cmd = r.take_u8()?.into();
r.advance(2)?; let streamid = StreamId::new(r.take_u16()?);
r.advance(4)?; let len = r.take_u16()? as usize;
if r.remaining() < len {
return Err(Error::InvalidMessage(
"Insufficient data in relay cell".into(),
));
}
r.truncate(len);
let msg = M::decode_from_reader(cmd, r)?;
Ok(Self { streamid, msg })
}
fn decode_v1_from_reader(r: &mut Reader<'_>) -> Result<Self> {
r.advance(16)?; let cmd: RelayCmd = r.take_u8()?.into();
let len = r.take_u16()?.into();
let streamid = match cmd.expects_streamid(Some(RelayCellFormat::V1)) {
StreamIdReq::WantNone => None,
StreamIdReq::WantSome => Some(StreamId::new(r.take_u16()?).ok_or_else(|| {
Error::InvalidMessage(
format!("Zero-valued stream ID with relay command {cmd}").into(),
)
})?),
StreamIdReq::Unrecognized | StreamIdReq::Any => {
return Err(Error::InvalidMessage(
format!("Unrecognized relay command {cmd}").into(),
));
}
};
if r.remaining() < len {
return Err(Error::InvalidMessage(
"Insufficient data in relay cell".into(),
));
}
r.truncate(len);
let msg = M::decode_from_reader(cmd, r)?;
Ok(Self { streamid, msg })
}
}
struct BodyWrapper(BoxedCellBody);
impl AsMut<[u8]> for BodyWrapper {
fn as_mut(&mut self) -> &mut [u8] {
self.0.as_mut()
}
}