use super::flow_ctrl::{Xoff, Xon};
use super::{RelayCellFormat, RelayCmd};
use crate::chancell::CELL_DATA_LEN;
use crate::chancell::msg::{
DestroyReason, HandshakeType, TAP_C_HANDSHAKE_LEN, TAP_S_HANDSHAKE_LEN,
};
use caret::caret_int;
use derive_deftly::Deftly;
use std::fmt::Write;
use std::net::{IpAddr, Ipv4Addr};
use std::num::NonZeroU8;
use tor_bytes::{EncodeError, EncodeResult, Error, Result};
use tor_bytes::{Readable, Reader, Writeable, Writer};
use tor_linkspec::EncodedLinkSpec;
use tor_llcrypto::pk::rsa::RsaIdentity;
use tor_llcrypto::util::ct::CtByteArray;
use tor_memquota::{derive_deftly_template_HasMemoryCost, memory_cost_structural_copy};
use bitflags::bitflags;
#[cfg(feature = "conflux")]
pub use super::conflux::{ConfluxLink, ConfluxLinked, ConfluxLinkedAck, ConfluxSwitch};
#[cfg(feature = "hs")]
pub use super::hs::{
EstablishRendezvous, IntroEstablished, Introduce1, Introduce2, IntroduceAck, Rendezvous1,
Rendezvous2, RendezvousEstablished, est_intro::EstablishIntro,
};
#[cfg(feature = "experimental-udp")]
pub use super::udp::{ConnectUdp, ConnectedUdp, Datagram};
crate::restrict::restricted_msg! {
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
#[non_exhaustive]
@omit_from "avoid_conflict_with_a_blanket_implementation"
pub enum AnyRelayMsg : RelayMsg {
Begin,
Data,
End,
Connected,
Sendme,
Extend,
Extended,
Extend2,
Extended2,
Truncate,
Truncated,
Drop,
Resolve,
Resolved,
BeginDir,
[feature = "experimental-udp"]
ConnectUdp,
[feature = "experimental-udp"]
ConnectedUdp,
[feature = "experimental-udp"]
Datagram,
[feature = "conflux"]
ConfluxLink,
[feature = "conflux"]
ConfluxLinked,
[feature = "conflux"]
ConfluxLinkedAck,
[feature = "conflux"]
ConfluxSwitch,
Xon,
Xoff,
[feature = "hs"]
EstablishIntro,
[feature = "hs"]
EstablishRendezvous,
[feature = "hs"]
Introduce1,
[feature = "hs"]
Introduce2,
[feature = "hs"]
Rendezvous1,
[feature = "hs"]
Rendezvous2,
[feature = "hs"]
IntroEstablished,
[feature = "hs"]
RendezvousEstablished,
[feature = "hs"]
IntroduceAck,
_ =>
Unrecognized,
}
}
pub trait Body: Sized {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self>;
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()>;
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct BeginFlags : u32 {
const IPV6_OKAY = (1<<0);
const IPV4_NOT_OKAY = (1<<1);
const IPV6_PREFERRED = (1<<2);
}
}
memory_cost_structural_copy!(BeginFlags);
impl From<u32> for BeginFlags {
fn from(v: u32) -> Self {
BeginFlags::from_bits_truncate(v)
}
}
#[derive(Clone, Default, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum IpVersionPreference {
Ipv4Only,
#[default]
Ipv4Preferred,
Ipv6Preferred,
Ipv6Only,
}
impl From<IpVersionPreference> for BeginFlags {
fn from(v: IpVersionPreference) -> Self {
use IpVersionPreference::*;
match v {
Ipv4Only => 0.into(),
Ipv4Preferred => BeginFlags::IPV6_OKAY,
Ipv6Preferred => BeginFlags::IPV6_OKAY | BeginFlags::IPV6_PREFERRED,
Ipv6Only => BeginFlags::IPV4_NOT_OKAY,
}
}
}
#[derive(Debug, Clone, PartialEq, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Begin {
addr: Vec<u8>,
port: u16,
flags: BeginFlags,
}
impl Begin {
pub fn new<F>(addr: &str, port: u16, flags: F) -> crate::Result<Self>
where
F: Into<BeginFlags>,
{
if !addr.is_ascii() {
return Err(crate::Error::BadStreamAddress);
}
let mut addr = addr.to_string();
addr.make_ascii_lowercase();
Ok(Begin {
addr: addr.into_bytes(),
port,
flags: flags.into(),
})
}
pub fn addr(&self) -> &[u8] {
&self.addr[..]
}
pub fn port(&self) -> u16 {
self.port
}
pub fn flags(&self) -> BeginFlags {
self.flags
}
}
impl Body for Begin {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let addr = {
if r.peek(1)? == b"[" {
r.advance(1)?;
let a = r.take_until(b']')?;
let colon = r.take_u8()?;
if colon != b':' {
return Err(Error::InvalidMessage("missing port in begin cell".into()));
}
a
} else {
r.take_until(b':')?
}
};
let port = r.take_until(0)?;
let flags = if r.remaining() >= 4 { r.take_u32()? } else { 0 };
if !addr.is_ascii() {
return Err(Error::InvalidMessage(
"target address in begin cell not ascii".into(),
));
}
let port = std::str::from_utf8(port)
.map_err(|_| Error::InvalidMessage("port in begin cell not utf8".into()))?;
let port = port
.parse()
.map_err(|_| Error::InvalidMessage("port in begin cell not a valid port".into()))?;
Ok(Begin {
addr: addr.into(),
port,
flags: flags.into(),
})
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
if self.addr.contains(&b':') {
w.write_u8(b'[');
w.write_all(&self.addr[..]);
w.write_u8(b']');
} else {
w.write_all(&self.addr[..]);
}
w.write_u8(b':');
w.write_all(self.port.to_string().as_bytes());
w.write_u8(0);
if self.flags.bits() != 0 {
w.write_u32(self.flags.bits());
}
Ok(())
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Data {
body: Vec<u8>,
}
impl Data {
pub const MAXLEN_V0: usize = CELL_DATA_LEN - 11;
pub const MAXLEN_V1: usize = CELL_DATA_LEN - 21;
pub const MAXLEN: usize = Data::MAXLEN_V0;
pub fn new(inp: &[u8]) -> crate::Result<Self> {
if inp.len() > Data::MAXLEN {
return Err(crate::Error::CantEncode("Data message too long"));
}
if inp.is_empty() {
return Err(crate::Error::CantEncode("Empty data message"));
}
Ok(Self::new_unchecked(inp.into()))
}
pub fn try_split_from(version: RelayCellFormat, inp: &[u8]) -> Option<(Self, &[u8])> {
if inp.is_empty() {
return None;
}
let upper_bound = Self::max_body_len(version);
let len = std::cmp::min(inp.len(), upper_bound);
let (data, remainder) = inp.split_at(len);
Some((Self::new_unchecked(data.into()), remainder))
}
fn new_unchecked(body: Vec<u8>) -> Self {
debug_assert!((1..=Data::MAXLEN).contains(&body.len()));
Data { body }
}
pub fn max_body_len(format: RelayCellFormat) -> usize {
match format {
RelayCellFormat::V0 => Self::MAXLEN_V0,
RelayCellFormat::V1 => Self::MAXLEN_V1,
}
}
}
impl From<Data> for Vec<u8> {
fn from(data: Data) -> Vec<u8> {
data.body
}
}
impl AsRef<[u8]> for Data {
fn as_ref(&self) -> &[u8] {
&self.body[..]
}
}
impl Body for Data {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
if r.remaining() == 0 {
return Err(Error::InvalidMessage("Empty DATA message".into()));
}
Ok(Data {
body: r.take(r.remaining())?.into(),
})
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.body);
Ok(())
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct End {
reason: EndReason,
addr: Option<(IpAddr, u32)>,
}
caret_int! {
#[derive(Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct EndReason(u8) {
MISC = 1,
RESOLVEFAILED = 2,
CONNECTREFUSED = 3,
EXITPOLICY = 4,
DESTROY = 5,
DONE = 6,
TIMEOUT = 7,
NOROUTE = 8,
HIBERNATING = 9,
INTERNAL = 10,
RESOURCELIMIT = 11,
CONNRESET = 12,
TORPROTOCOL = 13,
NOTDIRECTORY = 14,
}
}
impl tor_error::HasKind for EndReason {
fn kind(&self) -> tor_error::ErrorKind {
use EndReason as E;
use tor_error::ErrorKind as EK;
match *self {
E::MISC => EK::RemoteStreamError,
E::RESOLVEFAILED => EK::RemoteHostResolutionFailed,
E::CONNECTREFUSED => EK::RemoteConnectionRefused,
E::EXITPOLICY => EK::ExitPolicyRejected,
E::DESTROY => EK::CircuitCollapse,
E::DONE => EK::RemoteStreamClosed,
E::TIMEOUT => EK::ExitTimeout,
E::NOROUTE => EK::RemoteNetworkFailed,
E::RESOURCELIMIT | E::HIBERNATING => EK::RelayTooBusy,
E::INTERNAL | E::TORPROTOCOL | E::NOTDIRECTORY => EK::TorProtocolViolation,
E::CONNRESET => EK::RemoteStreamReset,
_ => EK::RemoteStreamError,
}
}
}
impl End {
pub fn new_misc() -> Self {
End {
reason: EndReason::MISC,
addr: None,
}
}
pub fn new_with_reason(reason: EndReason) -> Self {
End { reason, addr: None }
}
pub fn new_exitpolicy(addr: IpAddr, ttl: u32) -> Self {
End {
reason: EndReason::EXITPOLICY,
addr: Some((addr, ttl)),
}
}
pub fn reason(&self) -> EndReason {
self.reason
}
}
impl Body for End {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
if r.remaining() == 0 {
return Ok(End {
reason: EndReason::MISC,
addr: None,
});
}
let reason = r.take_u8()?.into();
if reason == EndReason::EXITPOLICY {
let addr = match r.remaining() {
4 | 8 => IpAddr::V4(r.extract()?),
16 | 20 => IpAddr::V6(r.extract()?),
_ => {
return Ok(End { reason, addr: None });
}
};
let ttl = if r.remaining() == 4 {
r.take_u32()?
} else {
u32::MAX
};
Ok(End {
reason,
addr: Some((addr, ttl)),
})
} else {
Ok(End { reason, addr: None })
}
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u8(self.reason.into());
if let (EndReason::EXITPOLICY, Some((addr, ttl))) = (self.reason, self.addr) {
match addr {
IpAddr::V4(v4) => w.write(&v4)?,
IpAddr::V6(v6) => w.write(&v6)?,
}
w.write_u32(ttl);
}
Ok(())
}
}
impl From<EndReason> for std::io::ErrorKind {
fn from(e: EndReason) -> Self {
use std::io::ErrorKind::*;
match e {
EndReason::RESOLVEFAILED => NotFound,
EndReason::CONNECTREFUSED => ConnectionRefused,
EndReason::EXITPOLICY => ConnectionRefused,
EndReason::DESTROY => ConnectionAborted,
EndReason::DONE => UnexpectedEof,
EndReason::TIMEOUT => TimedOut,
EndReason::HIBERNATING => ConnectionRefused,
EndReason::RESOURCELIMIT => ConnectionRefused,
EndReason::CONNRESET => ConnectionReset,
EndReason::TORPROTOCOL => InvalidData,
EndReason::NOTDIRECTORY => ConnectionRefused,
EndReason::INTERNAL | EndReason::NOROUTE | EndReason::MISC => Other,
_ => Other,
}
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Connected {
addr: Option<(IpAddr, u32)>,
}
impl Connected {
pub fn new_empty() -> Self {
Connected { addr: None }
}
pub fn new_with_addr(addr: IpAddr, ttl: u32) -> Self {
Connected {
addr: Some((addr, ttl)),
}
}
}
impl Body for Connected {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
if r.remaining() == 0 {
return Ok(Connected { addr: None });
}
let ipv4 = r.take_u32()?;
let addr = if ipv4 == 0 {
if r.take_u8()? != 6 {
return Err(Error::InvalidMessage(
"Invalid address type in CONNECTED cell".into(),
));
}
IpAddr::V6(r.extract()?)
} else {
IpAddr::V4(ipv4.into())
};
let ttl = r.take_u32()?;
Ok(Connected {
addr: Some((addr, ttl)),
})
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
if let Some((addr, ttl)) = self.addr {
match addr {
IpAddr::V4(v4) => w.write(&v4)?,
IpAddr::V6(v6) => {
w.write_u32(0);
w.write_u8(6);
w.write(&v6)?;
}
}
w.write_u32(ttl);
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct SendmeTag {
len: NonZeroU8,
tag: CtByteArray<20>,
}
impl From<[u8; 20]> for SendmeTag {
#[inline]
fn from(value: [u8; 20]) -> Self {
Self {
len: NonZeroU8::new(20).expect("20 was not nonzero?"),
tag: CtByteArray::from(value),
}
}
}
impl From<[u8; 16]> for SendmeTag {
#[inline]
fn from(value: [u8; 16]) -> Self {
let mut tag = CtByteArray::from([0; 20]);
tag.as_mut()[0..16].copy_from_slice(&value[..]);
Self {
len: NonZeroU8::new(16).expect("16 was not nonzero?"),
tag,
}
}
}
impl AsRef<[u8]> for SendmeTag {
fn as_ref(&self) -> &[u8] {
&self.tag.as_ref()[0..usize::from(u8::from(self.len))]
}
}
#[derive(Clone, Debug, thiserror::Error)]
#[non_exhaustive]
#[error("Invalid size {} on SENDME tag", len)]
pub struct InvalidSendmeTag {
len: usize,
}
impl From<InvalidSendmeTag> for tor_bytes::Error {
fn from(_: InvalidSendmeTag) -> Self {
tor_bytes::Error::BadLengthValue
}
}
impl<'a> TryFrom<&'a [u8]> for SendmeTag {
type Error = InvalidSendmeTag;
#[inline]
fn try_from(value: &'a [u8]) -> std::result::Result<Self, Self::Error> {
match value.len() {
16 => {
let a: [u8; 16] = value.try_into().expect("16 was not 16?");
Ok(Self::from(a))
}
20 => {
let a: [u8; 20] = value.try_into().expect("20 was not 20?");
Ok(Self::from(a))
}
_ => Err(InvalidSendmeTag { len: value.len() }),
}
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Sendme {
tag: Option<SendmeTag>,
}
impl Sendme {
pub fn new_empty() -> Self {
Sendme { tag: None }
}
pub fn new_tag(x: [u8; 20]) -> Self {
Sendme {
tag: Some(x.into()),
}
}
pub fn into_sendme_tag(self) -> Option<SendmeTag> {
self.tag
}
}
impl From<SendmeTag> for Sendme {
fn from(value: SendmeTag) -> Self {
Self { tag: Some(value) }
}
}
impl Body for Sendme {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let tag = if r.remaining() == 0 {
None
} else {
let ver = r.take_u8()?;
match ver {
0 => None,
1 => {
let dlen = r.take_u16()?;
Some(r.take(dlen as usize)?.try_into()?)
}
_ => {
return Err(Error::InvalidMessage("Unrecognized SENDME version.".into()));
}
}
};
Ok(Sendme { tag })
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
match self.tag {
None => (),
Some(x) => {
w.write_u8(1);
let x = x.as_ref();
let bodylen: u16 = x
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u16(bodylen);
w.write_all(x);
}
}
Ok(())
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Extend {
addr: Ipv4Addr,
port: u16,
handshake: Vec<u8>,
rsaid: RsaIdentity,
}
impl Extend {
pub fn new(addr: Ipv4Addr, port: u16, handshake: Vec<u8>, rsaid: RsaIdentity) -> Self {
Extend {
addr,
port,
handshake,
rsaid,
}
}
}
impl Body for Extend {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let addr = r.extract()?;
let port = r.take_u16()?;
let handshake = r.take(TAP_C_HANDSHAKE_LEN)?.into();
let rsaid = r.extract()?;
Ok(Extend {
addr,
port,
handshake,
rsaid,
})
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write(&self.addr)?;
w.write_u16(self.port);
w.write_all(&self.handshake[..]);
w.write(&self.rsaid)?;
Ok(())
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Extended {
handshake: Vec<u8>,
}
impl Extended {
pub fn new(handshake: Vec<u8>) -> Self {
Extended { handshake }
}
}
impl Body for Extended {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let handshake = r.take(TAP_S_HANDSHAKE_LEN)?.into();
Ok(Extended { handshake })
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.handshake);
Ok(())
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Extend2 {
linkspec: Vec<EncodedLinkSpec>,
handshake_type: HandshakeType,
handshake: Vec<u8>,
}
impl Extend2 {
pub fn new(
linkspec: Vec<EncodedLinkSpec>,
handshake_type: HandshakeType,
handshake: Vec<u8>,
) -> Self {
Extend2 {
linkspec,
handshake_type,
handshake,
}
}
pub fn handshake_type(&self) -> HandshakeType {
self.handshake_type
}
pub fn handshake(&self) -> &[u8] {
&self.handshake[..]
}
pub fn linkspecs(&self) -> &[EncodedLinkSpec] {
&self.linkspec
}
}
impl Body for Extend2 {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let n = r.take_u8()?;
let linkspec = r.extract_n(n as usize)?;
let handshake_type = r.take_u16()?.into();
let hlen = r.take_u16()?;
let handshake = r.take(hlen as usize)?.into();
Ok(Extend2 {
linkspec,
handshake_type,
handshake,
})
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
let n_linkspecs: u8 = self
.linkspec
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u8(n_linkspecs);
for ls in &self.linkspec {
w.write(ls)?;
}
w.write_u16(self.handshake_type.into());
let handshake_len: u16 = self
.handshake
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u16(handshake_len);
w.write_all(&self.handshake[..]);
Ok(())
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Extended2 {
handshake: Vec<u8>,
}
impl Extended2 {
pub fn new(handshake: Vec<u8>) -> Self {
Extended2 { handshake }
}
pub fn into_body(self) -> Vec<u8> {
self.handshake
}
}
impl Body for Extended2 {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let hlen = r.take_u16()?;
let handshake = r.take(hlen as usize)?;
Ok(Extended2 {
handshake: handshake.into(),
})
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
let handshake_len: u16 = self
.handshake
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u16(handshake_len);
w.write_all(&self.handshake[..]);
Ok(())
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Truncated {
reason: DestroyReason,
}
impl Truncated {
pub fn new(reason: DestroyReason) -> Self {
Truncated { reason }
}
pub fn reason(self) -> DestroyReason {
self.reason
}
}
impl Body for Truncated {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Ok(Truncated {
reason: r.take_u8()?.into(),
})
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u8(self.reason.into());
Ok(())
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Resolve {
query: Vec<u8>,
}
impl Resolve {
pub fn new(s: &str) -> Self {
Resolve {
query: s.as_bytes().into(),
}
}
pub fn new_reverse(addr: &IpAddr) -> Self {
let query = match addr {
IpAddr::V4(v4) => {
let [a, b, c, d] = v4.octets();
format!("{}.{}.{}.{}.in-addr.arpa", d, c, b, a)
}
IpAddr::V6(v6) => {
let mut s = String::with_capacity(72);
for o in v6.octets().iter().rev() {
let high_nybble = o >> 4;
let low_nybble = o & 15;
write!(s, "{:x}.{:x}.", low_nybble, high_nybble)
.expect("write to string failed");
}
write!(s, "ip6.arpa").expect("write to string failed");
s
}
};
Resolve {
query: query.into_bytes(),
}
}
}
impl Body for Resolve {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let query = r.take_until(0)?;
Ok(Resolve {
query: query.into(),
})
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.query[..]);
w.write_u8(0);
Ok(())
}
}
#[derive(Debug, Clone, Eq, PartialEq, Deftly)]
#[derive_deftly(HasMemoryCost)]
#[non_exhaustive]
pub enum ResolvedVal {
Ip(IpAddr),
Hostname(Vec<u8>),
TransientError,
NontransientError,
Unrecognized(u8, Vec<u8>),
}
const RES_HOSTNAME: u8 = 0;
const RES_IPV4: u8 = 4;
const RES_IPV6: u8 = 6;
const RES_ERR_TRANSIENT: u8 = 0xF0;
const RES_ERR_NONTRANSIENT: u8 = 0xF1;
impl Readable for ResolvedVal {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
fn res_len(tp: u8) -> Option<usize> {
match tp {
RES_IPV4 => Some(4),
RES_IPV6 => Some(16),
_ => None,
}
}
let tp = r.take_u8()?;
let len = r.take_u8()? as usize;
if let Some(expected_len) = res_len(tp) {
if len != expected_len {
return Err(Error::InvalidMessage(
"Wrong length for RESOLVED answer".into(),
));
}
}
Ok(match tp {
RES_HOSTNAME => Self::Hostname(r.take(len)?.into()),
RES_IPV4 => Self::Ip(IpAddr::V4(r.extract()?)),
RES_IPV6 => Self::Ip(IpAddr::V6(r.extract()?)),
RES_ERR_TRANSIENT => {
r.advance(len)?;
Self::TransientError
}
RES_ERR_NONTRANSIENT => {
r.advance(len)?;
Self::NontransientError
}
_ => Self::Unrecognized(tp, r.take(len)?.into()),
})
}
}
impl Writeable for ResolvedVal {
fn write_onto<B: Writer + ?Sized>(&self, w: &mut B) -> EncodeResult<()> {
match self {
Self::Hostname(h) => {
w.write_u8(RES_HOSTNAME);
let h_len: u8 = h
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u8(h_len);
w.write_all(&h[..]);
}
Self::Ip(IpAddr::V4(a)) => {
w.write_u8(RES_IPV4);
w.write_u8(4); w.write(a)?;
}
Self::Ip(IpAddr::V6(a)) => {
w.write_u8(RES_IPV6);
w.write_u8(16); w.write(a)?;
}
Self::TransientError => {
w.write_u8(RES_ERR_TRANSIENT);
w.write_u8(0); }
Self::NontransientError => {
w.write_u8(RES_ERR_NONTRANSIENT);
w.write_u8(0); }
Self::Unrecognized(tp, v) => {
w.write_u8(*tp);
let v_len: u8 = v
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u8(v_len);
w.write_all(&v[..]);
}
}
Ok(())
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Resolved {
answers: Vec<(ResolvedVal, u32)>,
}
impl Resolved {
pub fn new_empty() -> Self {
Resolved {
answers: Vec::new(),
}
}
pub fn new_err(transient: bool, ttl: u32) -> Self {
let mut res = Self::new_empty();
let err = if transient {
ResolvedVal::TransientError
} else {
ResolvedVal::NontransientError
};
res.add_answer(err, ttl);
res
}
pub fn add_answer(&mut self, answer: ResolvedVal, ttl: u32) {
self.answers.push((answer, ttl));
}
pub fn into_answers(self) -> Vec<(ResolvedVal, u32)> {
self.answers
}
}
impl Body for Resolved {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let mut answers = Vec::new();
while r.remaining() > 0 {
let rv = r.extract()?;
let ttl = r.take_u32()?;
answers.push((rv, ttl));
}
Ok(Resolved { answers })
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
for (rv, ttl) in &self.answers {
w.write(rv)?;
w.write_u32(*ttl);
}
Ok(())
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Unrecognized {
cmd: RelayCmd,
body: Vec<u8>,
}
impl Unrecognized {
pub fn new<B>(cmd: RelayCmd, body: B) -> Self
where
B: Into<Vec<u8>>,
{
let body = body.into();
Unrecognized { cmd, body }
}
pub fn cmd(&self) -> RelayCmd {
self.cmd
}
pub fn decode_with_cmd(cmd: RelayCmd, r: &mut Reader<'_>) -> Result<Self> {
let mut r = Unrecognized::decode_from_reader(r)?;
r.cmd = cmd;
Ok(r)
}
}
impl Body for Unrecognized {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Ok(Unrecognized {
cmd: 0.into(),
body: r.take(r.remaining())?.into(),
})
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.body[..]);
Ok(())
}
}
macro_rules! empty_body {
{
$(#[$meta:meta])*
pub struct $name:ident {}
} => {
$(#[$meta])*
#[derive(Clone,Debug,Default,derive_deftly::Deftly)]
#[derive_deftly(tor_memquota::HasMemoryCost)]
#[non_exhaustive]
pub struct $name {}
impl $crate::relaycell::msg::Body for $name {
fn decode_from_reader(_r: &mut Reader<'_>) -> Result<Self> {
Ok(Self::default())
}
fn encode_onto<W: Writer + ?Sized>(self, _w: &mut W) -> EncodeResult<()> {
Ok(())
}
}
}
}
#[allow(unused_imports)] pub(crate) use empty_body;
empty_body! {
pub struct Drop {}
}
empty_body! {
pub struct Truncate {}
}
empty_body! {
pub struct BeginDir {}
}
macro_rules! msg_impl_relaymsg {
($($body:ident),* $(,)?) =>
{paste::paste!{
$(impl crate::relaycell::RelayMsg for $body {
fn cmd(&self) -> crate::relaycell::RelayCmd { crate::relaycell::RelayCmd::[< $body:snake:upper >] }
fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()> {
crate::relaycell::msg::Body::encode_onto(self, w)
}
fn decode_from_reader(cmd: RelayCmd, r: &mut tor_bytes::Reader<'_>) -> tor_bytes::Result<Self> {
if cmd != crate::relaycell::RelayCmd::[< $body:snake:upper >] {
return Err(tor_bytes::Error::InvalidMessage(
format!("Expected {} command; got {cmd}", stringify!([< $body:snake:upper >])).into()
));
}
crate::relaycell::msg::Body::decode_from_reader(r)
}
}
impl TryFrom<AnyRelayMsg> for $body {
type Error = crate::Error;
fn try_from(msg: AnyRelayMsg) -> crate::Result<$body> {
use crate::relaycell::RelayMsg;
match msg {
AnyRelayMsg::$body(b) => Ok(b),
_ => Err(crate::Error::CircProto(format!("Expected {}; got {}" ,
stringify!([<$body:snake:upper>]),
msg.cmd())) ),
}
}
}
)*
}}
}
msg_impl_relaymsg!(
Begin, Data, End, Connected, Sendme, Extend, Extended, Extend2, Extended2, Truncate, Truncated,
Drop, Resolve, Resolved, BeginDir,
);
#[cfg(feature = "experimental-udp")]
msg_impl_relaymsg!(ConnectUdp, ConnectedUdp, Datagram);
#[cfg(feature = "hs")]
msg_impl_relaymsg!(
EstablishIntro,
EstablishRendezvous,
Introduce1,
Introduce2,
Rendezvous1,
Rendezvous2,
IntroEstablished,
RendezvousEstablished,
IntroduceAck,
);
#[cfg(feature = "conflux")]
msg_impl_relaymsg!(ConfluxSwitch, ConfluxLink, ConfluxLinked, ConfluxLinkedAck);
msg_impl_relaymsg!(Xon, Xoff);
#[cfg(test)]
mod test {
#![allow(clippy::bool_assert_comparison)]
#![allow(clippy::clone_on_copy)]
#![allow(clippy::dbg_macro)]
#![allow(clippy::mixed_attributes_style)]
#![allow(clippy::print_stderr)]
#![allow(clippy::print_stdout)]
#![allow(clippy::single_char_pattern)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::unchecked_time_subtraction)]
#![allow(clippy::useless_vec)]
#![allow(clippy::needless_pass_by_value)]
use super::*;
#[test]
fn sendme_tags() {
let ts: Vec<SendmeTag> = vec![
(*b"Yea, on the word of ").into(),
(*b"a Bloom, ye shal").into(),
(*b"l ere long enter int").into(),
(*b"o the golden cit").into(),
];
for (i1, i2) in (0..4).zip(0..4) {
if i1 == i2 {
assert_eq!(ts[i1], ts[i2]);
} else {
assert_ne!(ts[i1], ts[i2]);
}
}
assert_eq!(ts[0].as_ref(), &b"Yea, on the word of "[..]);
assert_eq!(ts[3].as_ref(), &b"o the golden cit"[..]);
assert_eq!(ts[1], b"a Bloom, ye shal"[..].try_into().unwrap());
assert_eq!(ts[2], b"l ere long enter int"[..].try_into().unwrap());
assert!(matches!(
SendmeTag::try_from(&b"o the golden ci"[..]),
Err(InvalidSendmeTag { .. }),
));
}
}