use super::{BoxedCellBody, CELL_DATA_LEN, ChanCmd, RawCellBody};
use std::net::{IpAddr, Ipv4Addr};
use tor_basic_utils::skip_fmt;
use tor_bytes::{self, EncodeError, EncodeResult, Error, Readable, Reader, Result, Writer};
use tor_memquota::derive_deftly_template_HasMemoryCost;
use tor_units::IntegerMilliseconds;
use caret::caret_int;
use derive_deftly::Deftly;
use educe::Educe;
pub trait Body: Readable {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
r.extract()
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()>;
}
crate::restrict::restricted_msg! {
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
#[non_exhaustive]
@omit_from "avoid_conflict_with_a_blanket_implementation"
pub enum AnyChanMsg : ChanMsg {
Padding,
Vpadding,
Create,
CreateFast,
Create2,
Created,
CreatedFast,
Created2,
Relay,
RelayEarly,
Destroy,
Netinfo,
Versions,
PaddingNegotiate,
Certs,
AuthChallenge,
Authenticate,
_ =>
Unrecognized,
}
}
#[derive(Clone, Debug, Default, Deftly)]
#[derive_deftly(HasMemoryCost)]
#[non_exhaustive]
pub struct Padding {}
impl Padding {
pub fn new() -> Self {
Padding {}
}
}
impl Body for Padding {
fn encode_onto<W: Writer + ?Sized>(self, _w: &mut W) -> EncodeResult<()> {
Ok(())
}
}
impl Readable for Padding {
fn take_from(_b: &mut Reader<'_>) -> Result<Self> {
Ok(Padding {})
}
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Vpadding {
len: u16,
}
impl Vpadding {
pub fn new(len: u16) -> Self {
Vpadding { len }
}
}
impl Body for Vpadding {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_zeros(self.len as usize);
Ok(())
}
}
impl Readable for Vpadding {
fn take_from(b: &mut Reader<'_>) -> Result<Self> {
if b.remaining() > u16::MAX as usize {
return Err(Error::InvalidMessage(
"Too many bytes in VPADDING cell".into(),
));
}
Ok(Vpadding {
len: b.remaining() as u16,
})
}
}
macro_rules! fixed_len_handshake {
{
$(#[$meta:meta])*
$name:ident , $cmd:ident, $len:ident
} => {
$(#[$meta])*
#[derive(Clone,Debug,Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct $name {
handshake: Vec<u8>
}
impl $name {
pub fn new<B>(handshake: B) -> Self
where B: Into<Vec<u8>>
{
let handshake = handshake.into();
$name { handshake }
}
}
impl Body for $name {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.handshake[..]);
Ok(())
}
}
impl Readable for $name {
fn take_from(b: &mut Reader<'_>) -> Result<Self> {
Ok($name {
handshake: b.take($len)?.into(),
})
}
}
}
}
pub(crate) const TAP_C_HANDSHAKE_LEN: usize = 128 + 16 + 42;
pub(crate) const TAP_S_HANDSHAKE_LEN: usize = 128 + 20;
const FAST_C_HANDSHAKE_LEN: usize = 20;
const FAST_S_HANDSHAKE_LEN: usize = 20 + 20;
fixed_len_handshake! {
Create, CREATE, TAP_C_HANDSHAKE_LEN
}
fixed_len_handshake! {
Created, CREATED, TAP_S_HANDSHAKE_LEN
}
fixed_len_handshake! {
CreateFast, CREATE_FAST, FAST_C_HANDSHAKE_LEN
}
impl CreateFast {
pub fn handshake(&self) -> &[u8] {
&self.handshake
}
}
fixed_len_handshake! {
CreatedFast, CREATED_FAST, FAST_S_HANDSHAKE_LEN
}
impl CreatedFast {
pub fn into_handshake(self) -> Vec<u8> {
self.handshake
}
}
caret_int! {
#[derive(Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct HandshakeType(u16) {
TAP = 0,
NTOR = 2,
NTOR_V3 = 3,
}
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Create2 {
handshake_type: HandshakeType,
handshake: Vec<u8>,
}
impl Body for Create2 {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u16(self.handshake_type.into());
let handshake_len = self
.handshake
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u16(handshake_len);
w.write_all(&self.handshake[..]);
Ok(())
}
}
impl Readable for Create2 {
fn take_from(b: &mut Reader<'_>) -> Result<Self> {
let handshake_type = HandshakeType::from(b.take_u16()?);
let hlen = b.take_u16()?;
let handshake = b.take(hlen as usize)?.into();
Ok(Create2 {
handshake_type,
handshake,
})
}
}
impl Create2 {
pub fn new<B>(handshake_type: HandshakeType, handshake: B) -> Self
where
B: Into<Vec<u8>>,
{
let handshake = handshake.into();
Create2 {
handshake_type,
handshake,
}
}
pub fn handshake_type(&self) -> HandshakeType {
self.handshake_type
}
pub fn body(&self) -> &[u8] {
&self.handshake[..]
}
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Created2 {
handshake: Vec<u8>,
}
impl Created2 {
pub fn new<B>(handshake: B) -> Self
where
B: Into<Vec<u8>>,
{
let handshake = handshake.into();
Created2 { handshake }
}
pub fn into_body(self) -> Vec<u8> {
self.handshake
}
}
impl Body for Created2 {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
let handshake_len = self
.handshake
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u16(handshake_len);
w.write_all(&self.handshake[..]);
Ok(())
}
}
impl Readable for Created2 {
fn take_from(b: &mut Reader<'_>) -> Result<Self> {
let hlen = b.take_u16()?;
let handshake = b.take(hlen as usize)?.into();
Ok(Created2 { handshake })
}
}
#[derive(Clone, Educe, derive_more::From, Deftly)]
#[derive_deftly(HasMemoryCost)]
#[educe(Debug)]
pub struct Relay {
#[educe(Debug(method = "skip_fmt"))]
body: BoxedCellBody,
}
impl Relay {
pub fn new<P>(body: P) -> Self
where
P: AsRef<[u8]>,
{
let body = body.as_ref();
let mut r = [0_u8; CELL_DATA_LEN];
r[..body.len()].copy_from_slice(body);
Relay { body: Box::new(r) }
}
pub fn from_raw(body: RawCellBody) -> Self {
Relay {
body: Box::new(body),
}
}
pub fn into_relay_body(self) -> BoxedCellBody {
self.body
}
pub fn into_early(self) -> AnyChanMsg {
AnyChanMsg::RelayEarly(RelayEarly(self))
}
}
impl Body for Relay {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.body[..]);
Ok(())
}
}
impl Readable for Relay {
fn take_from(b: &mut Reader<'_>) -> Result<Self> {
let mut body = Box::new([0_u8; CELL_DATA_LEN]);
body.copy_from_slice(b.take(CELL_DATA_LEN)?);
Ok(Relay { body })
}
}
#[derive(Clone, Debug, derive_more::Deref, derive_more::From, derive_more::Into, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct RelayEarly(Relay);
impl Readable for RelayEarly {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
Ok(RelayEarly(Relay::take_from(r)?))
}
}
impl Body for RelayEarly {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
self.0.encode_onto(w)
}
}
impl RelayEarly {
pub fn into_relay_body(self) -> BoxedCellBody {
self.0.body
}
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Destroy {
reason: DestroyReason,
}
impl Destroy {
pub fn new(reason: DestroyReason) -> Self {
Destroy { reason }
}
pub fn reason(&self) -> DestroyReason {
self.reason
}
}
impl Body for Destroy {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u8(self.reason.into());
Ok(())
}
}
impl Readable for Destroy {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let reason = r.take_u8()?.into();
Ok(Destroy { reason })
}
}
caret_int! {
#[derive(Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct DestroyReason(u8) {
NONE = 0,
PROTOCOL = 1,
INTERNAL = 2,
REQUESTED = 3,
HIBERNATING = 4,
RESOURCELIMIT = 5,
CONNECTFAILED = 6,
OR_IDENTITY = 7,
CHANNEL_CLOSED = 8,
FINISHED = 9,
TIMEOUT = 10,
DESTROYED = 11,
NOSUCHSERVICE = 12
}
}
impl DestroyReason {
pub fn human_str(&self) -> &'static str {
match *self {
DestroyReason::NONE => "No reason",
DestroyReason::PROTOCOL => "Protocol violation",
DestroyReason::INTERNAL => "Internal error",
DestroyReason::REQUESTED => "Client sent a TRUNCATE command",
DestroyReason::HIBERNATING => "Relay is hibernating and not accepting requests",
DestroyReason::RESOURCELIMIT => "Relay ran out of resources",
DestroyReason::CONNECTFAILED => "Couldn't connect to relay",
DestroyReason::OR_IDENTITY => "Connected to relay with different OR identity",
DestroyReason::CHANNEL_CLOSED => "The OR channels carrying this circuit died",
DestroyReason::FINISHED => "Circuit expired for being too dirty or old",
DestroyReason::TIMEOUT => "Circuit construction took too long",
DestroyReason::DESTROYED => "Circuit was destroyed without client truncate",
DestroyReason::NOSUCHSERVICE => "No such onion service",
_ => "Unrecognized reason",
}
}
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Netinfo {
timestamp: u32,
their_addr: Option<IpAddr>,
my_addr: Vec<IpAddr>,
}
fn enc_one_netinfo_addr<W: Writer + ?Sized>(w: &mut W, addr: &IpAddr) {
match addr {
IpAddr::V4(ipv4) => {
w.write_u8(0x04); w.write_u8(4); w.write_all(&ipv4.octets()[..]);
}
IpAddr::V6(ipv6) => {
w.write_u8(0x06); w.write_u8(16); w.write_all(&ipv6.octets()[..]);
}
}
}
fn take_one_netinfo_addr(r: &mut Reader<'_>) -> Result<Option<IpAddr>> {
let atype = r.take_u8()?;
let alen = r.take_u8()?;
let abody = r.take(alen as usize)?;
match (atype, alen) {
(0x04, 4) => {
let bytes = [abody[0], abody[1], abody[2], abody[3]];
Ok(Some(IpAddr::V4(bytes.into())))
}
(0x06, 16) => {
let mut bytes = [0_u8; 16];
bytes.copy_from_slice(abody);
Ok(Some(IpAddr::V6(bytes.into())))
}
(_, _) => Ok(None),
}
}
impl Netinfo {
pub fn from_client(their_addr: Option<IpAddr>) -> Self {
Netinfo {
timestamp: 0, their_addr,
my_addr: Vec::new(), }
}
pub fn from_relay<V>(timestamp: u32, their_addr: Option<IpAddr>, my_addrs: V) -> Self
where
V: Into<Vec<IpAddr>>,
{
let my_addr = my_addrs.into();
Netinfo {
timestamp,
their_addr,
my_addr,
}
}
pub fn timestamp(&self) -> Option<std::time::SystemTime> {
use std::time::{Duration, SystemTime};
if self.timestamp == 0 {
None
} else {
Some(SystemTime::UNIX_EPOCH + Duration::from_secs(self.timestamp.into()))
}
}
pub fn their_addr(&self) -> Option<&IpAddr> {
self.their_addr.as_ref()
}
pub fn my_addrs(&self) -> &[IpAddr] {
&self.my_addr
}
}
impl Body for Netinfo {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u32(self.timestamp);
let their_addr = self
.their_addr
.unwrap_or_else(|| Ipv4Addr::UNSPECIFIED.into());
enc_one_netinfo_addr(w, &their_addr);
let n_addrs: u8 = self
.my_addr
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u8(n_addrs);
for addr in &self.my_addr {
enc_one_netinfo_addr(w, addr);
}
Ok(())
}
}
impl Readable for Netinfo {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let timestamp = r.take_u32()?;
let their_addr = take_one_netinfo_addr(r)?.filter(|a| !a.is_unspecified());
let my_n_addrs = r.take_u8()?;
let mut my_addr = Vec::with_capacity(my_n_addrs as usize);
for _ in 0..my_n_addrs {
if let Some(a) = take_one_netinfo_addr(r)? {
my_addr.push(a);
}
}
Ok(Netinfo {
timestamp,
their_addr,
my_addr,
})
}
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Versions {
versions: Vec<u16>,
}
impl Versions {
pub fn new<B>(vs: B) -> crate::Result<Self>
where
B: Into<Vec<u16>>,
{
let versions = vs.into();
if versions.len() < (u16::MAX / 2) as usize {
Ok(Self { versions })
} else {
Err(crate::Error::CantEncode("Too many versions"))
}
}
pub fn encode_for_handshake(self) -> EncodeResult<Vec<u8>> {
let mut v = Vec::new();
v.write_u16(0); v.write_u8(ChanCmd::VERSIONS.into());
v.write_u16((self.versions.len() * 2) as u16); self.encode_onto(&mut v)?;
Ok(v)
}
pub fn best_shared_link_protocol(&self, my_protos: &[u16]) -> Option<u16> {
let p = my_protos
.iter()
.filter(|p| self.versions.contains(p))
.fold(0_u16, |a, b| u16::max(a, *b));
if p == 0 { None } else { Some(p) }
}
}
impl Body for Versions {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
for v in &self.versions {
w.write_u16(*v);
}
Ok(())
}
}
impl Readable for Versions {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let mut versions = Vec::new();
while r.remaining() > 0 {
versions.push(r.take_u16()?);
}
Ok(Versions { versions })
}
}
caret_int! {
#[derive(Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct PaddingNegotiateCmd(u8) {
START = 2,
STOP = 1,
}
}
#[derive(Clone, Debug, Eq, PartialEq, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct PaddingNegotiate {
command: PaddingNegotiateCmd,
ito_low_ms: u16,
ito_high_ms: u16,
}
impl PaddingNegotiate {
pub fn start_default() -> Self {
Self {
command: PaddingNegotiateCmd::START,
ito_low_ms: 0,
ito_high_ms: 0,
}
}
pub fn start(ito_low: IntegerMilliseconds<u16>, ito_high: IntegerMilliseconds<u16>) -> Self {
Self {
command: PaddingNegotiateCmd::START,
ito_low_ms: ito_low.as_millis(),
ito_high_ms: ito_high.as_millis(),
}
}
pub fn stop() -> Self {
Self {
command: PaddingNegotiateCmd::STOP,
ito_low_ms: 0,
ito_high_ms: 0,
}
}
#[cfg(feature = "testing")]
pub fn from_raw(command: PaddingNegotiateCmd, ito_low_ms: u16, ito_high_ms: u16) -> Self {
PaddingNegotiate {
command,
ito_low_ms,
ito_high_ms,
}
}
}
impl Default for PaddingNegotiate {
fn default() -> Self {
Self::start_default()
}
}
impl Body for PaddingNegotiate {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u8(0); w.write_u8(self.command.get());
w.write_u16(self.ito_low_ms);
w.write_u16(self.ito_high_ms);
Ok(())
}
}
impl Readable for PaddingNegotiate {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let v = r.take_u8()?;
if v != 0 {
return Err(Error::InvalidMessage(
"Unrecognized padding negotiation version".into(),
));
}
let command = r.take_u8()?.into();
let ito_low_ms = r.take_u16()?;
let ito_high_ms = r.take_u16()?;
Ok(PaddingNegotiate {
command,
ito_low_ms,
ito_high_ms,
})
}
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
struct TorCert {
certtype: u8,
cert: Vec<u8>,
}
fn enc_one_tor_cert<W: Writer + ?Sized>(w: &mut W, c: &TorCert) -> EncodeResult<()> {
w.write_u8(c.certtype);
let cert_len: u16 = c
.cert
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u16(cert_len);
w.write_all(&c.cert[..]);
Ok(())
}
fn take_one_tor_cert(r: &mut Reader<'_>) -> Result<TorCert> {
let certtype = r.take_u8()?;
let certlen = r.take_u16()?;
let cert = r.take(certlen as usize)?;
Ok(TorCert {
certtype,
cert: cert.into(),
})
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Certs {
certs: Vec<TorCert>,
}
impl Certs {
pub fn new_empty() -> Self {
Certs { certs: Vec::new() }
}
pub fn push_cert_body<B>(&mut self, certtype: tor_cert::CertType, cert: B)
where
B: Into<Vec<u8>>,
{
let certtype = certtype.into();
let cert = cert.into();
self.certs.push(TorCert { certtype, cert });
}
#[cfg(feature = "relay")]
pub fn push_cert<C>(&mut self, cert: &C)
where
C: tor_cert::EncodedCert,
{
self.push_cert_body(cert.cert_type(), cert.encoded());
}
pub fn cert_body(&self, tp: tor_cert::CertType) -> Option<&[u8]> {
let tp: u8 = tp.into();
self.certs
.iter()
.find(|c| c.certtype == tp)
.map(|c| &c.cert[..])
}
pub fn parse_ed_cert(&self, tp: tor_cert::CertType) -> crate::Result<tor_cert::KeyUnknownCert> {
let body = self
.cert_body(tp)
.ok_or_else(|| crate::Error::ChanProto(format!("Missing {} certificate", tp)))?;
let cert = tor_cert::Ed25519Cert::decode(body).map_err(|be| crate::Error::BytesErr {
err: be,
parsed: "ed25519 certificate",
})?;
if cert.peek_cert_type() != tp {
return Err(crate::Error::ChanProto(format!(
"Found a {} certificate labeled as {}",
cert.peek_cert_type(),
tp
)));
}
Ok(cert)
}
}
impl Body for Certs {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
let n_certs: u8 = self
.certs
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u8(n_certs);
for c in &self.certs {
enc_one_tor_cert(w, c)?;
}
Ok(())
}
}
impl Readable for Certs {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let n = r.take_u8()?;
let mut certs = Vec::new();
for _ in 0..n {
certs.push(take_one_tor_cert(r)?);
}
Ok(Certs { certs })
}
}
const CHALLENGE_LEN: usize = 32;
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct AuthChallenge {
challenge: [u8; CHALLENGE_LEN],
methods: Vec<u16>,
}
impl AuthChallenge {
pub fn new<B, M>(challenge: B, methods: M) -> Self
where
B: Into<[u8; CHALLENGE_LEN]>,
M: Into<Vec<u16>>,
{
AuthChallenge {
challenge: challenge.into(),
methods: methods.into(),
}
}
pub fn methods(&self) -> &[u16] {
&self.methods
}
}
impl Body for AuthChallenge {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.challenge[..]);
let n_methods = self
.methods
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u16(n_methods);
for m in self.methods {
w.write_u16(m);
}
Ok(())
}
}
impl Readable for AuthChallenge {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let challenge = r.extract()?;
let n_methods = r.take_u16()?;
let mut methods = Vec::new();
for _ in 0..n_methods {
methods.push(r.take_u16()?);
}
Ok(AuthChallenge { challenge, methods })
}
}
#[derive(Clone, Debug, Deftly, Eq, PartialEq)]
#[derive_deftly(HasMemoryCost)]
pub struct Authenticate {
authtype: u16,
auth: Vec<u8>,
}
impl Authenticate {
const SIG_LEN: usize = 64;
pub fn new<B>(authtype: u16, body: B) -> Self
where
B: Into<Vec<u8>>,
{
Authenticate {
authtype,
auth: body.into(),
}
}
pub fn auth_type(&self) -> u16 {
self.authtype
}
pub fn body_no_rand(&self) -> Result<&[u8]> {
const RAND_LEN: usize = 24;
let body = self.body()?;
let body_end_offset = body.len().checked_sub(RAND_LEN).ok_or(Error::MissingData)?;
Ok(&body[..body_end_offset])
}
pub fn body(&self) -> Result<&[u8]> {
let auth = self.auth();
let sig_end_offset = auth
.len()
.checked_sub(Self::SIG_LEN)
.ok_or(Error::MissingData)?;
Ok(&auth[..sig_end_offset])
}
pub fn auth(&self) -> &[u8] {
&self.auth
}
pub fn sig(&self) -> Result<&[u8; Self::SIG_LEN]> {
let auth = self.auth();
let sig_start_offset = auth
.len()
.checked_sub(Self::SIG_LEN)
.ok_or(Error::MissingData)?;
(&self.auth[sig_start_offset..])
.try_into()
.map_err(|_| Error::Bug(tor_error::internal!("Failed to get signature bytes")))
}
}
impl Body for Authenticate {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u16(self.authtype);
let authlen = self
.auth
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u16(authlen);
w.write_all(&self.auth[..]);
Ok(())
}
}
impl Readable for Authenticate {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
let authtype = r.take_u16()?;
let authlen = r.take_u16()?;
let auth = r.take(authlen as usize)?.into();
Ok(Authenticate { authtype, auth })
}
}
#[derive(Clone, Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct Unrecognized {
cmd: ChanCmd,
content: Vec<u8>,
}
impl Unrecognized {
pub fn new<B>(cmd: ChanCmd, content: B) -> Self
where
B: Into<Vec<u8>>,
{
let content = content.into();
Unrecognized { cmd, content }
}
pub fn cmd(&self) -> ChanCmd {
self.cmd
}
pub fn decode_with_cmd(cmd: ChanCmd, r: &mut Reader<'_>) -> Result<Unrecognized> {
let mut u = Unrecognized::take_from(r)?;
u.cmd = cmd;
Ok(u)
}
}
impl Body for Unrecognized {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.content[..]);
Ok(())
}
}
impl Readable for Unrecognized {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
Ok(Unrecognized {
cmd: 0.into(),
content: r.take(r.remaining())?.into(),
})
}
}
macro_rules! msg_into_cell {
($body:ident) => {
impl From<$body> for super::AnyChanCell {
fn from(body: $body) -> super::AnyChanCell {
super::AnyChanCell {
circid: None,
msg: body.into(),
}
}
}
};
}
msg_into_cell!(Padding);
msg_into_cell!(Vpadding);
msg_into_cell!(Netinfo);
msg_into_cell!(Versions);
msg_into_cell!(PaddingNegotiate);
msg_into_cell!(Certs);
msg_into_cell!(AuthChallenge);
msg_into_cell!(Authenticate);
macro_rules! msg_impl_chanmsg {
($($body:ident,)*) =>
{paste::paste!{
$(impl crate::chancell::ChanMsg for $body {
fn cmd(&self) -> crate::chancell::ChanCmd { crate::chancell::ChanCmd::[< $body:snake:upper >] }
fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()> {
crate::chancell::msg::Body::encode_onto(self, w)
}
fn decode_from_reader(cmd: ChanCmd, r: &mut tor_bytes::Reader<'_>) -> tor_bytes::Result<Self> {
if cmd != crate::chancell::ChanCmd::[< $body:snake:upper >] {
return Err(tor_bytes::Error::InvalidMessage(
format!("Expected {} command; got {cmd}", stringify!([< $body:snake:upper >])).into()
));
}
crate::chancell::msg::Body::decode_from_reader(r)
}
})*
}}
}
msg_impl_chanmsg!(
Padding,
Vpadding,
Create,
CreateFast,
Create2,
Created,
CreatedFast,
Created2,
Relay,
RelayEarly,
Destroy,
Netinfo,
Versions,
PaddingNegotiate,
Certs,
AuthChallenge,
Authenticate,
);
#[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 destroy_reason() {
let r1 = DestroyReason::CONNECTFAILED;
assert_eq!(r1.human_str(), "Couldn't connect to relay");
let r2 = DestroyReason::from(200); assert_eq!(r2.human_str(), "Unrecognized reason");
}
}