tor_cell/relaycell/
msg.rs

1//! Encoding and decoding for relay messages
2//!
3//! Relay messages are sent along circuits, inside RELAY or RELAY_EARLY
4//! cells.
5
6use super::flow_ctrl::{Xoff, Xon};
7use super::{RelayCellFormat, RelayCmd};
8use crate::chancell::msg::{
9    DestroyReason, HandshakeType, TAP_C_HANDSHAKE_LEN, TAP_S_HANDSHAKE_LEN,
10};
11use crate::chancell::CELL_DATA_LEN;
12use caret::caret_int;
13use derive_deftly::Deftly;
14use std::fmt::Write;
15use std::net::{IpAddr, Ipv4Addr};
16use std::num::NonZeroU8;
17use tor_bytes::{EncodeError, EncodeResult, Error, Result};
18use tor_bytes::{Readable, Reader, Writeable, Writer};
19use tor_linkspec::EncodedLinkSpec;
20use tor_llcrypto::pk::rsa::RsaIdentity;
21use tor_llcrypto::util::ct::CtByteArray;
22use tor_memquota::{derive_deftly_template_HasMemoryCost, memory_cost_structural_copy};
23
24use bitflags::bitflags;
25
26#[cfg(feature = "conflux")]
27#[cfg_attr(docsrs, doc(cfg(feature = "conflux")))]
28pub use super::conflux::{ConfluxLink, ConfluxLinked, ConfluxLinkedAck, ConfluxSwitch};
29
30#[cfg(feature = "hs")]
31#[cfg_attr(docsrs, doc(cfg(feature = "hs")))]
32pub use super::hs::{
33    est_intro::EstablishIntro, EstablishRendezvous, IntroEstablished, Introduce1, Introduce2,
34    IntroduceAck, Rendezvous1, Rendezvous2, RendezvousEstablished,
35};
36#[cfg(feature = "experimental-udp")]
37#[cfg_attr(docsrs, doc(cfg(feature = "experimental-udp")))]
38pub use super::udp::{ConnectUdp, ConnectedUdp, Datagram};
39
40crate::restrict::restricted_msg! {
41/// A single parsed relay message, sent or received along a circuit
42#[derive(Debug, Clone, Deftly)]
43#[derive_deftly(HasMemoryCost)]
44#[non_exhaustive]
45@omit_from "avoid_conflict_with_a_blanket_implementation"
46pub enum AnyRelayMsg : RelayMsg {
47    /// Create a stream
48    Begin,
49    /// Send data on a stream
50    Data,
51    /// Close a stream
52    End,
53    /// Successful response to a Begin message
54    Connected,
55    /// For flow control
56    Sendme,
57    /// Extend a circuit to a new hop (deprecated)
58    Extend,
59    /// Successful response to an Extend message (deprecated)
60    Extended,
61    /// Extend a circuit to a new hop
62    Extend2,
63    /// Successful response to an Extend2 message
64    Extended2,
65    /// Partially close a circuit
66    Truncate,
67    /// Tell the client that a circuit has been partially closed
68    Truncated,
69    /// Used for padding
70    Drop,
71    /// Launch a DNS request
72    Resolve,
73    /// Response to a Resolve message
74    Resolved,
75    /// Start a directory stream
76    BeginDir,
77    /// Start a UDP stream.
78    [feature = "experimental-udp"]
79    ConnectUdp,
80    /// Successful response to a ConnectUdp message
81    [feature = "experimental-udp"]
82    ConnectedUdp,
83    /// UDP stream data
84    [feature = "experimental-udp"]
85    Datagram,
86    /// Link circuits together at the receiving endpoint
87    [feature = "conflux"]
88    ConfluxLink,
89    /// Confirm that the circuits were linked
90    [feature = "conflux"]
91    ConfluxLinked,
92    /// Acknowledge the linkage of the circuits, for RTT measurement.
93    [feature = "conflux"]
94    ConfluxLinkedAck,
95    /// Switch to another leg in an already linked circuit construction.
96    [feature = "conflux"]
97    ConfluxSwitch,
98    /// Update a stream's transmit rate limit.
99    Xon,
100    /// Disable transmitting on a stream.
101    Xoff,
102    /// Establish Introduction
103    [feature = "hs"]
104    EstablishIntro,
105    /// Establish Rendezvous
106    [feature = "hs"]
107    EstablishRendezvous,
108    /// Introduce1 (client to introduction point)
109    [feature = "hs"]
110    Introduce1,
111    /// Introduce2 (introduction point to service)
112    [feature = "hs"]
113    Introduce2,
114    /// Rendezvous1 (service to rendezvous point)
115    [feature = "hs"]
116    Rendezvous1,
117    /// Rendezvous2 (rendezvous point to client)
118    [feature = "hs"]
119    Rendezvous2,
120    /// Acknowledgement for EstablishIntro.
121    [feature = "hs"]
122    IntroEstablished,
123    /// Acknowledgment for EstablishRendezvous.
124    [feature = "hs"]
125    RendezvousEstablished,
126    /// Acknowledgement for Introduce1.
127    [feature = "hs"]
128    IntroduceAck,
129
130    _ =>
131    /// An unrecognized command.
132    Unrecognized,
133    }
134}
135
136/// Internal: traits in common different cell bodies.
137pub trait Body: Sized {
138    /// Decode a relay cell body from a provided reader.
139    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self>;
140    /// Encode the body of this cell into the end of a writer.
141    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()>;
142}
143
144bitflags! {
145    /// A set of recognized flags that can be attached to a begin cell.
146    ///
147    /// For historical reasons, these flags are constructed so that 0
148    /// is a reasonable default for all of them.
149    #[derive(Clone, Copy, Debug)]
150    pub struct BeginFlags : u32 {
151        /// The client would accept a connection to an IPv6 address.
152        const IPV6_OKAY = (1<<0);
153        /// The client would not accept a connection to an IPv4 address.
154        const IPV4_NOT_OKAY = (1<<1);
155        /// The client would rather have a connection to an IPv6 address.
156        const IPV6_PREFERRED = (1<<2);
157    }
158}
159memory_cost_structural_copy!(BeginFlags);
160impl From<u32> for BeginFlags {
161    fn from(v: u32) -> Self {
162        BeginFlags::from_bits_truncate(v)
163    }
164}
165
166/// A preference for IPv4 vs IPv6 addresses; usable as a nicer frontend for
167/// BeginFlags.
168#[derive(Clone, Default, Copy, Debug, Eq, PartialEq)]
169#[non_exhaustive]
170pub enum IpVersionPreference {
171    /// Only IPv4 is allowed.
172    Ipv4Only,
173    /// IPv4 and IPv6 are both allowed, and IPv4 is preferred.
174    #[default]
175    Ipv4Preferred,
176    /// IPv4 and IPv6 are both allowed, and IPv6 is preferred.
177    Ipv6Preferred,
178    /// Only IPv6 is allowed.
179    Ipv6Only,
180}
181impl From<IpVersionPreference> for BeginFlags {
182    fn from(v: IpVersionPreference) -> Self {
183        use IpVersionPreference::*;
184        match v {
185            Ipv4Only => 0.into(),
186            Ipv4Preferred => BeginFlags::IPV6_OKAY,
187            Ipv6Preferred => BeginFlags::IPV6_OKAY | BeginFlags::IPV6_PREFERRED,
188            Ipv6Only => BeginFlags::IPV4_NOT_OKAY,
189        }
190    }
191}
192
193/// A Begin message creates a new data stream.
194///
195/// Upon receiving a Begin message, relays should try to open a new stream
196/// for the client, if their exit policy permits, and associate it with a
197/// new TCP connection to the target address.
198///
199/// If the exit decides to reject the Begin message, or if the TCP
200/// connection fails, the exit should send an End message.
201///
202/// Clients should reject these messages.
203#[derive(Debug, Clone, Deftly)]
204#[derive_deftly(HasMemoryCost)]
205pub struct Begin {
206    /// Ascii string describing target address
207    addr: Vec<u8>,
208    /// Target port
209    port: u16,
210    /// Flags that describe how to resolve the address
211    flags: BeginFlags,
212}
213
214impl Begin {
215    /// Construct a new Begin cell
216    pub fn new<F>(addr: &str, port: u16, flags: F) -> crate::Result<Self>
217    where
218        F: Into<BeginFlags>,
219    {
220        if !addr.is_ascii() {
221            return Err(crate::Error::BadStreamAddress);
222        }
223        let mut addr = addr.to_string();
224        addr.make_ascii_lowercase();
225        Ok(Begin {
226            addr: addr.into_bytes(),
227            port,
228            flags: flags.into(),
229        })
230    }
231
232    /// Return the address requested in this message.
233    pub fn addr(&self) -> &[u8] {
234        &self.addr[..]
235    }
236
237    /// Return the port requested by this message.
238    pub fn port(&self) -> u16 {
239        self.port
240    }
241
242    /// Return the set of flags provided in this message.
243    pub fn flags(&self) -> BeginFlags {
244        self.flags
245    }
246}
247
248impl Body for Begin {
249    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
250        let addr = {
251            if r.peek(1)? == b"[" {
252                // IPv6 address
253                r.advance(1)?;
254                let a = r.take_until(b']')?;
255                let colon = r.take_u8()?;
256                if colon != b':' {
257                    return Err(Error::InvalidMessage("missing port in begin cell".into()));
258                }
259                a
260            } else {
261                // IPv4 address, or hostname.
262                r.take_until(b':')?
263            }
264        };
265        let port = r.take_until(0)?;
266        let flags = if r.remaining() >= 4 { r.take_u32()? } else { 0 };
267
268        if !addr.is_ascii() {
269            return Err(Error::InvalidMessage(
270                "target address in begin cell not ascii".into(),
271            ));
272        }
273
274        let port = std::str::from_utf8(port)
275            .map_err(|_| Error::InvalidMessage("port in begin cell not utf8".into()))?;
276
277        let port = port
278            .parse()
279            .map_err(|_| Error::InvalidMessage("port in begin cell not a valid port".into()))?;
280
281        Ok(Begin {
282            addr: addr.into(),
283            port,
284            flags: flags.into(),
285        })
286    }
287    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
288        if self.addr.contains(&b':') {
289            w.write_u8(b'[');
290            w.write_all(&self.addr[..]);
291            w.write_u8(b']');
292        } else {
293            w.write_all(&self.addr[..]);
294        }
295        w.write_u8(b':');
296        w.write_all(self.port.to_string().as_bytes());
297        w.write_u8(0);
298        if self.flags.bits() != 0 {
299            w.write_u32(self.flags.bits());
300        }
301        Ok(())
302    }
303}
304
305/// A Data message represents data sent along a stream.
306///
307/// Upon receiving a Data message for a live stream, the client or
308/// exit sends that data onto the associated TCP connection.
309///
310/// These messages hold between 1 and [Data::MAXLEN] bytes of data each;
311/// they are the most numerous messages on the Tor network.
312#[derive(Debug, Clone, Deftly)]
313#[derive_deftly(HasMemoryCost)]
314pub struct Data {
315    /// Contents of the cell, to be sent on a specific stream
316    ///
317    /// INVARIANT: Holds between 1 and [`Data::MAXLEN`] bytes, inclusive.
318    //
319    // TODO: There's a good case to be made that this should be a BoxedCellBody
320    // instead, to avoid allocations and copies.  But first probably we should
321    // figure out how proposal 340 will work with this.  Possibly, we will wind
322    // up using `bytes` or something.
323    body: Vec<u8>,
324}
325impl Data {
326    /// The longest allowable body length for a single V0 data cell.
327    ///
328    /// Relay command (1) + 'Recognized' (2) + StreamID (2) + Digest (4) + Length (2) = 11
329    pub const MAXLEN_V0: usize = CELL_DATA_LEN - 11;
330
331    /// The longest allowable body length for a single V1 data cell.
332    ///
333    /// Tag (16) + Relay command (1) + Length (2) + StreamID (2) = 21
334    pub const MAXLEN_V1: usize = CELL_DATA_LEN - 21;
335
336    /// The longest allowable body length for any data cell.
337    ///
338    /// Note that this value is too large to fit into a v1 relay cell;
339    /// see [`MAXLEN_V1`](Data::MAXLEN_V1) if you are making a v1 data cell.
340    ///
341    pub const MAXLEN: usize = Data::MAXLEN_V0;
342
343    /// Construct a new data cell.
344    ///
345    /// Returns an error if `inp` is longer than [`Data::MAXLEN`] bytes.
346    pub fn new(inp: &[u8]) -> crate::Result<Self> {
347        if inp.len() > Data::MAXLEN {
348            return Err(crate::Error::CantEncode("Data message too long"));
349        }
350        if inp.is_empty() {
351            return Err(crate::Error::CantEncode("Empty data message"));
352        }
353        Ok(Self::new_unchecked(inp.into()))
354    }
355
356    /// Construct a new data cell, taking as many bytes from `inp`
357    /// as possible.
358    ///
359    /// Return the data cell, and a slice holding any bytes that
360    /// wouldn't fit (if any).
361    ///
362    /// Returns None if the input was empty.
363    pub fn try_split_from(version: RelayCellFormat, inp: &[u8]) -> Option<(Self, &[u8])> {
364        if inp.is_empty() {
365            return None;
366        }
367        let upper_bound = Self::max_body_len(version);
368        let len = std::cmp::min(inp.len(), upper_bound);
369        let (data, remainder) = inp.split_at(len);
370        Some((Self::new_unchecked(data.into()), remainder))
371    }
372
373    /// Construct a new data cell from a provided vector of bytes.
374    ///
375    /// The vector _must_ not have more than [`Data::MAXLEN`] bytes, and must
376    /// not be empty.
377    fn new_unchecked(body: Vec<u8>) -> Self {
378        debug_assert!((1..=Data::MAXLEN).contains(&body.len()));
379        Data { body }
380    }
381
382    /// Return the maximum allowable body length for a Data message
383    /// using the provided `format`.
384    pub fn max_body_len(format: RelayCellFormat) -> usize {
385        match format {
386            RelayCellFormat::V0 => Self::MAXLEN_V0,
387            RelayCellFormat::V1 => Self::MAXLEN_V1,
388        }
389    }
390}
391impl From<Data> for Vec<u8> {
392    fn from(data: Data) -> Vec<u8> {
393        data.body
394    }
395}
396impl AsRef<[u8]> for Data {
397    fn as_ref(&self) -> &[u8] {
398        &self.body[..]
399    }
400}
401
402impl Body for Data {
403    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
404        if r.remaining() == 0 {
405            return Err(Error::InvalidMessage("Empty DATA message".into()));
406        }
407        Ok(Data {
408            body: r.take(r.remaining())?.into(),
409        })
410    }
411    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
412        w.write_all(&self.body);
413        Ok(())
414    }
415}
416
417/// An End message tells the other end of the circuit to close a stream.
418///
419/// Note that End messages do not implement a true half-closed state,
420/// so after sending an End message each party needs to wait a while
421/// to be sure that the stream is completely dead.
422#[derive(Debug, Clone, Deftly)]
423#[derive_deftly(HasMemoryCost)]
424pub struct End {
425    /// Reason for closing the stream
426    reason: EndReason,
427    /// If the reason is EXITPOLICY, this holds the resolved address an
428    /// associated TTL.  The TTL is set to MAX if none was given.
429    addr: Option<(IpAddr, u32)>,
430}
431
432caret_int! {
433    /// A declared reason for closing a stream
434    #[derive(Deftly)]
435    #[derive_deftly(HasMemoryCost)]
436    pub struct EndReason(u8) {
437        /// Closing a stream because of an unspecified reason.
438        ///
439        /// This is the only END reason that clients send.
440        MISC = 1,
441        /// Couldn't look up hostname.
442        RESOLVEFAILED = 2,
443        /// Remote host refused connection.
444        CONNECTREFUSED = 3,
445        /// Closing a stream because of an exit-policy violation.
446        EXITPOLICY = 4,
447        /// Circuit destroyed
448        DESTROY = 5,
449        /// Anonymized TCP connection was closed
450        DONE = 6,
451        /// Connection timed out, or OR timed out while connecting
452        TIMEOUT = 7,
453        /// No route to target destination.
454        NOROUTE = 8,
455        /// OR is entering hibernation and not handling requests
456        HIBERNATING = 9,
457        /// Internal error at the OR
458        INTERNAL = 10,
459        /// Ran out of resources to fulfill requests
460        RESOURCELIMIT = 11,
461        /// Connection unexpectedly reset
462        CONNRESET = 12,
463        /// Tor protocol violation
464        TORPROTOCOL = 13,
465        /// BEGIN_DIR cell at a non-directory-cache.
466        NOTDIRECTORY = 14,
467    }
468}
469
470impl tor_error::HasKind for EndReason {
471    fn kind(&self) -> tor_error::ErrorKind {
472        use tor_error::ErrorKind as EK;
473        use EndReason as E;
474        match *self {
475            E::MISC => EK::RemoteStreamError,
476            E::RESOLVEFAILED => EK::RemoteHostResolutionFailed,
477            E::CONNECTREFUSED => EK::RemoteConnectionRefused,
478            E::EXITPOLICY => EK::ExitPolicyRejected,
479            E::DESTROY => EK::CircuitCollapse,
480            E::DONE => EK::RemoteStreamClosed,
481            E::TIMEOUT => EK::ExitTimeout,
482            E::NOROUTE => EK::RemoteNetworkFailed,
483            E::RESOURCELIMIT | E::HIBERNATING => EK::RelayTooBusy,
484            E::INTERNAL | E::TORPROTOCOL | E::NOTDIRECTORY => EK::TorProtocolViolation,
485            E::CONNRESET => EK::RemoteStreamReset,
486            _ => EK::RemoteStreamError,
487        }
488    }
489}
490
491impl End {
492    /// Make a new END_REASON_MISC message.
493    ///
494    /// Clients send this every time they decide to close a stream.
495    pub fn new_misc() -> Self {
496        End {
497            reason: EndReason::MISC,
498            addr: None,
499        }
500    }
501    /// Make a new END message with the provided end reason.
502    pub fn new_with_reason(reason: EndReason) -> Self {
503        End { reason, addr: None }
504    }
505    /// Make a new END message with END_REASON_EXITPOLICY, and the
506    /// provided address and ttl.
507    pub fn new_exitpolicy(addr: IpAddr, ttl: u32) -> Self {
508        End {
509            reason: EndReason::EXITPOLICY,
510            addr: Some((addr, ttl)),
511        }
512    }
513    /// Return the provided EndReason for this End cell.
514    pub fn reason(&self) -> EndReason {
515        self.reason
516    }
517}
518impl Body for End {
519    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
520        if r.remaining() == 0 {
521            return Ok(End {
522                reason: EndReason::MISC,
523                addr: None,
524            });
525        }
526        let reason = r.take_u8()?.into();
527        if reason == EndReason::EXITPOLICY {
528            let addr = match r.remaining() {
529                4 | 8 => IpAddr::V4(r.extract()?),
530                16 | 20 => IpAddr::V6(r.extract()?),
531                _ => {
532                    // Ignores other message lengths.
533                    return Ok(End { reason, addr: None });
534                }
535            };
536            let ttl = if r.remaining() == 4 {
537                r.take_u32()?
538            } else {
539                u32::MAX
540            };
541            Ok(End {
542                reason,
543                addr: Some((addr, ttl)),
544            })
545        } else {
546            Ok(End { reason, addr: None })
547        }
548    }
549    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
550        w.write_u8(self.reason.into());
551        if let (EndReason::EXITPOLICY, Some((addr, ttl))) = (self.reason, self.addr) {
552            match addr {
553                IpAddr::V4(v4) => w.write(&v4)?,
554                IpAddr::V6(v6) => w.write(&v6)?,
555            }
556            w.write_u32(ttl);
557        }
558        Ok(())
559    }
560}
561
562impl From<EndReason> for std::io::ErrorKind {
563    fn from(e: EndReason) -> Self {
564        use std::io::ErrorKind::*;
565        match e {
566            EndReason::RESOLVEFAILED => NotFound,
567            EndReason::CONNECTREFUSED => ConnectionRefused,
568            EndReason::EXITPOLICY => ConnectionRefused,
569            EndReason::DESTROY => ConnectionAborted,
570            EndReason::DONE => UnexpectedEof,
571            EndReason::TIMEOUT => TimedOut,
572            EndReason::HIBERNATING => ConnectionRefused,
573            EndReason::RESOURCELIMIT => ConnectionRefused,
574            EndReason::CONNRESET => ConnectionReset,
575            EndReason::TORPROTOCOL => InvalidData,
576            EndReason::NOTDIRECTORY => ConnectionRefused,
577            EndReason::INTERNAL | EndReason::NOROUTE | EndReason::MISC => Other,
578            _ => Other,
579        }
580    }
581}
582
583/// A Connected message is a successful response to a Begin message
584///
585/// When an outgoing connection succeeds, the exit sends a Connected
586/// back to the client.
587///
588/// Clients never send Connected messages.
589#[derive(Debug, Clone, Deftly)]
590#[derive_deftly(HasMemoryCost)]
591pub struct Connected {
592    /// Resolved address and TTL (time to live) in seconds
593    addr: Option<(IpAddr, u32)>,
594}
595impl Connected {
596    /// Construct a new empty connected cell.
597    pub fn new_empty() -> Self {
598        Connected { addr: None }
599    }
600    /// Construct a connected cell with an address and a time-to-live value.
601    pub fn new_with_addr(addr: IpAddr, ttl: u32) -> Self {
602        Connected {
603            addr: Some((addr, ttl)),
604        }
605    }
606}
607impl Body for Connected {
608    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
609        if r.remaining() == 0 {
610            return Ok(Connected { addr: None });
611        }
612        let ipv4 = r.take_u32()?;
613        let addr = if ipv4 == 0 {
614            if r.take_u8()? != 6 {
615                return Err(Error::InvalidMessage(
616                    "Invalid address type in CONNECTED cell".into(),
617                ));
618            }
619            IpAddr::V6(r.extract()?)
620        } else {
621            IpAddr::V4(ipv4.into())
622        };
623        let ttl = r.take_u32()?;
624
625        Ok(Connected {
626            addr: Some((addr, ttl)),
627        })
628    }
629    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
630        if let Some((addr, ttl)) = self.addr {
631            match addr {
632                IpAddr::V4(v4) => w.write(&v4)?,
633                IpAddr::V6(v6) => {
634                    w.write_u32(0);
635                    w.write_u8(6);
636                    w.write(&v6)?;
637                }
638            }
639            w.write_u32(ttl);
640        }
641        Ok(())
642    }
643}
644
645/// An authentication tag to use for circuit-level SENDME messages.
646///
647/// It is either a 20-byte tag (used with Tor1 encryption),
648/// or a 16-byte tag (used with CGO encryption).
649#[derive(Debug, Clone, Copy, Eq, PartialEq, Deftly)]
650#[derive_deftly(HasMemoryCost)]
651pub struct SendmeTag {
652    /// The number of bytes present in the tag.
653    /// Always equal to 16 or 20.
654    ///
655    /// We use a NonZeroU8 here so Rust can use its niche optimization.
656    len: NonZeroU8,
657    /// The actual contents of the tag.
658    ///
659    /// Tags above 20 bytes long are always an error.
660    ///
661    /// Unused bytes are always set to zero, so we can derive PartialEq.
662    tag: CtByteArray<20>,
663}
664impl From<[u8; 20]> for SendmeTag {
665    // In experimentation, these "inlines" were necessary for good generated asm.
666    #[inline]
667    fn from(value: [u8; 20]) -> Self {
668        Self {
669            len: NonZeroU8::new(20).expect("20 was not nonzero?"),
670            tag: CtByteArray::from(value),
671        }
672    }
673}
674impl From<[u8; 16]> for SendmeTag {
675    // In experimentation, these "inlines" were necessary for good generated asm.
676    #[inline]
677    fn from(value: [u8; 16]) -> Self {
678        let mut tag = CtByteArray::from([0; 20]);
679        tag.as_mut()[0..16].copy_from_slice(&value[..]);
680        Self {
681            len: NonZeroU8::new(16).expect("16 was not nonzero?"),
682            tag,
683        }
684    }
685}
686impl AsRef<[u8]> for SendmeTag {
687    fn as_ref(&self) -> &[u8] {
688        &self.tag.as_ref()[0..usize::from(u8::from(self.len))]
689    }
690}
691/// An error from attempting to decode a SENDME tag.
692#[derive(Clone, Debug, thiserror::Error)]
693#[non_exhaustive]
694#[error("Invalid size {} on SENDME tag", len)]
695pub struct InvalidSendmeTag {
696    /// The length of the invalid tag.
697    len: usize,
698}
699impl From<InvalidSendmeTag> for tor_bytes::Error {
700    fn from(_: InvalidSendmeTag) -> Self {
701        tor_bytes::Error::BadLengthValue
702    }
703}
704
705impl<'a> TryFrom<&'a [u8]> for SendmeTag {
706    type Error = InvalidSendmeTag;
707
708    // In experimentation, this "inline" was especially necessary for good generated asm.
709    #[inline]
710    fn try_from(value: &'a [u8]) -> std::result::Result<Self, Self::Error> {
711        match value.len() {
712            16 => {
713                let a: [u8; 16] = value.try_into().expect("16 was not 16?");
714                Ok(Self::from(a))
715            }
716            20 => {
717                let a: [u8; 20] = value.try_into().expect("20 was not 20?");
718                Ok(Self::from(a))
719            }
720            _ => Err(InvalidSendmeTag { len: value.len() }),
721        }
722    }
723}
724
725/// A Sendme message is used to increase flow-control windows.
726///
727/// To avoid congestion, each Tor circuit and stream keeps track of a
728/// number of data cells that it is willing to send.  It decrements
729/// these numbers every time it sends a cell.  If these numbers reach
730/// zero, then no more cells can be sent on the stream or circuit.
731///
732/// The only way to re-increment these numbers is by receiving a
733/// Sendme cell from the other end of the circuit or stream.
734///
735/// For security, current circuit-level Sendme cells include an
736/// authentication tag that proves knowledge of the cells that they are
737/// acking.
738///
739/// See [tor-spec.txt](https://spec.torproject.org/tor-spec) for more
740/// information; also see the source for `tor_proto::circuit::sendme`.
741#[derive(Debug, Clone, Deftly)]
742#[derive_deftly(HasMemoryCost)]
743pub struct Sendme {
744    /// A tag value authenticating the previously received data.
745    tag: Option<SendmeTag>,
746}
747impl Sendme {
748    /// Return a new empty sendme cell
749    ///
750    /// This format is used on streams, and on circuits without sendme
751    /// authentication.
752    pub fn new_empty() -> Self {
753        Sendme { tag: None }
754    }
755    /// This format is used on circuits with sendme authentication.
756    pub fn new_tag(x: [u8; 20]) -> Self {
757        Sendme {
758            tag: Some(x.into()),
759        }
760    }
761    /// Consume this cell and return its authentication tag, if any
762    pub fn into_sendme_tag(self) -> Option<SendmeTag> {
763        self.tag
764    }
765}
766impl From<SendmeTag> for Sendme {
767    fn from(value: SendmeTag) -> Self {
768        Self { tag: Some(value) }
769    }
770}
771impl Body for Sendme {
772    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
773        let tag = if r.remaining() == 0 {
774            None
775        } else {
776            let ver = r.take_u8()?;
777            match ver {
778                0 => None,
779                1 => {
780                    let dlen = r.take_u16()?;
781                    Some(r.take(dlen as usize)?.try_into()?)
782                }
783                _ => {
784                    return Err(Error::InvalidMessage("Unrecognized SENDME version.".into()));
785                }
786            }
787        };
788        Ok(Sendme { tag })
789    }
790    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
791        match self.tag {
792            None => (),
793            Some(x) => {
794                w.write_u8(1);
795                let x = x.as_ref();
796                let bodylen: u16 = x
797                    .len()
798                    .try_into()
799                    .map_err(|_| EncodeError::BadLengthValue)?;
800                w.write_u16(bodylen);
801                w.write_all(x);
802            }
803        }
804        Ok(())
805    }
806}
807
808/// Extend was an obsolete circuit extension message format.
809///
810/// This format only handled IPv4 addresses, RSA identities, and the
811/// TAP handshake.  Modern Tor clients use Extend2 instead.
812#[derive(Debug, Clone, Deftly)]
813#[derive_deftly(HasMemoryCost)]
814pub struct Extend {
815    /// Where to extend to (address)
816    addr: Ipv4Addr,
817    /// Where to extend to (port)
818    port: u16,
819    /// A TAP handshake to send
820    handshake: Vec<u8>,
821    /// The RSA identity of the target relay
822    rsaid: RsaIdentity,
823}
824impl Extend {
825    /// Construct a new (deprecated) extend cell
826    pub fn new(addr: Ipv4Addr, port: u16, handshake: Vec<u8>, rsaid: RsaIdentity) -> Self {
827        Extend {
828            addr,
829            port,
830            handshake,
831            rsaid,
832        }
833    }
834}
835impl Body for Extend {
836    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
837        let addr = r.extract()?;
838        let port = r.take_u16()?;
839        let handshake = r.take(TAP_C_HANDSHAKE_LEN)?.into();
840        let rsaid = r.extract()?;
841        Ok(Extend {
842            addr,
843            port,
844            handshake,
845            rsaid,
846        })
847    }
848    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
849        w.write(&self.addr)?;
850        w.write_u16(self.port);
851        w.write_all(&self.handshake[..]);
852        w.write(&self.rsaid)?;
853        Ok(())
854    }
855}
856
857/// Extended was an obsolete circuit extension message, sent in reply to
858/// an Extend message.
859///
860/// Like Extend, the Extended message was only designed for the TAP
861/// handshake.
862#[derive(Debug, Clone, Deftly)]
863#[derive_deftly(HasMemoryCost)]
864pub struct Extended {
865    /// Contents of the handshake sent in response to the EXTEND
866    handshake: Vec<u8>,
867}
868impl Extended {
869    /// Construct a new Extended message with the provided handshake
870    pub fn new(handshake: Vec<u8>) -> Self {
871        Extended { handshake }
872    }
873}
874impl Body for Extended {
875    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
876        let handshake = r.take(TAP_S_HANDSHAKE_LEN)?.into();
877        Ok(Extended { handshake })
878    }
879    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
880        w.write_all(&self.handshake);
881        Ok(())
882    }
883}
884
885/// An Extend2 message tells the last relay in a circuit to extend to a new
886/// hop.
887///
888/// When a relay (call it R) receives an Extend2 message, it tries to
889/// find (or make) a channel to the other relay (R') described in the
890/// list of link specifiers. (A link specifier can be an IP addresses
891/// or a cryptographic identity).  Once R has such a channel, the
892/// it packages the client's handshake data as a new Create2 message
893/// R'.  If R' replies with a Created2 (success) message, R packages
894/// that message's contents in an Extended message.
895//
896/// Unlike Extend messages, Extend2 messages can encode any handshake
897/// type, and can describe relays in ways other than IPv4 addresses
898/// and RSA identities.
899#[derive(Debug, Clone, Deftly)]
900#[derive_deftly(HasMemoryCost)]
901pub struct Extend2 {
902    /// A vector of "link specifiers"
903    ///
904    /// These link specifiers describe where to find the target relay
905    /// that the recipient should extend to.  They include things like
906    /// IP addresses and identity keys.
907    linkspec: Vec<EncodedLinkSpec>,
908    /// Type of handshake to be sent in a CREATE2 cell
909    handshake_type: HandshakeType,
910    /// Body of the handshake to be sent in a CREATE2 cell
911    handshake: Vec<u8>,
912}
913impl Extend2 {
914    /// Create a new Extend2 cell.
915    pub fn new(
916        linkspec: Vec<EncodedLinkSpec>,
917        handshake_type: HandshakeType,
918        handshake: Vec<u8>,
919    ) -> Self {
920        Extend2 {
921            linkspec,
922            handshake_type,
923            handshake,
924        }
925    }
926
927    /// Return the type of this handshake.
928    pub fn handshake_type(&self) -> HandshakeType {
929        self.handshake_type
930    }
931
932    /// Return the inner handshake for this Extend2 cell.
933    pub fn handshake(&self) -> &[u8] {
934        &self.handshake[..]
935    }
936}
937
938impl Body for Extend2 {
939    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
940        let n = r.take_u8()?;
941        let linkspec = r.extract_n(n as usize)?;
942        let handshake_type = r.take_u16()?.into();
943        let hlen = r.take_u16()?;
944        let handshake = r.take(hlen as usize)?.into();
945        Ok(Extend2 {
946            linkspec,
947            handshake_type,
948            handshake,
949        })
950    }
951    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
952        let n_linkspecs: u8 = self
953            .linkspec
954            .len()
955            .try_into()
956            .map_err(|_| EncodeError::BadLengthValue)?;
957        w.write_u8(n_linkspecs);
958        for ls in &self.linkspec {
959            w.write(ls)?;
960        }
961        w.write_u16(self.handshake_type.into());
962        let handshake_len: u16 = self
963            .handshake
964            .len()
965            .try_into()
966            .map_err(|_| EncodeError::BadLengthValue)?;
967        w.write_u16(handshake_len);
968        w.write_all(&self.handshake[..]);
969        Ok(())
970    }
971}
972
973/// Extended2 is a successful reply to an Extend2 message.
974///
975/// Extended2 messages are generated by the former last hop of a
976/// circuit, to tell the client that they have successfully completed
977/// a handshake on the client's behalf.
978#[derive(Debug, Clone, Deftly)]
979#[derive_deftly(HasMemoryCost)]
980pub struct Extended2 {
981    /// Contents of the CREATED2 cell that the new final hop sent in
982    /// response
983    handshake: Vec<u8>,
984}
985impl Extended2 {
986    /// Construct a new Extended2 message with the provided handshake
987    pub fn new(handshake: Vec<u8>) -> Self {
988        Extended2 { handshake }
989    }
990    /// Consume this extended2 cell and return its body.
991    pub fn into_body(self) -> Vec<u8> {
992        self.handshake
993    }
994}
995impl Body for Extended2 {
996    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
997        let hlen = r.take_u16()?;
998        let handshake = r.take(hlen as usize)?;
999        Ok(Extended2 {
1000            handshake: handshake.into(),
1001        })
1002    }
1003    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
1004        let handshake_len: u16 = self
1005            .handshake
1006            .len()
1007            .try_into()
1008            .map_err(|_| EncodeError::BadLengthValue)?;
1009        w.write_u16(handshake_len);
1010        w.write_all(&self.handshake[..]);
1011        Ok(())
1012    }
1013}
1014
1015/// A Truncated message is sent to the client when the remaining hops
1016/// of a circuit have gone away.
1017///
1018/// NOTE: Current Tor implementations often treat Truncated messages and
1019/// Destroy messages interchangeably.  Truncated was intended to be a
1020/// "soft" Destroy, that would leave the unaffected parts of a circuit
1021/// still usable.
1022#[derive(Debug, Clone, Deftly)]
1023#[derive_deftly(HasMemoryCost)]
1024pub struct Truncated {
1025    /// Reason for which this circuit was truncated.
1026    reason: DestroyReason,
1027}
1028impl Truncated {
1029    /// Construct a new truncated message.
1030    pub fn new(reason: DestroyReason) -> Self {
1031        Truncated { reason }
1032    }
1033    /// Get the provided reason to truncate the circuit.
1034    pub fn reason(self) -> DestroyReason {
1035        self.reason
1036    }
1037}
1038impl Body for Truncated {
1039    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
1040        Ok(Truncated {
1041            reason: r.take_u8()?.into(),
1042        })
1043    }
1044    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
1045        w.write_u8(self.reason.into());
1046        Ok(())
1047    }
1048}
1049
1050/// A Resolve message launches a DNS lookup stream.
1051///
1052/// A client sends a Resolve message when it wants to perform a DNS
1053/// lookup _without_ connecting to the resulting address.  On success
1054/// the exit responds with a Resolved message; on failure it responds
1055/// with an End message.
1056#[derive(Debug, Clone, Deftly)]
1057#[derive_deftly(HasMemoryCost)]
1058pub struct Resolve {
1059    /// Ascii-encoded address to resolve
1060    query: Vec<u8>,
1061}
1062impl Resolve {
1063    /// Construct a new resolve message to look up a hostname.
1064    pub fn new(s: &str) -> Self {
1065        Resolve {
1066            query: s.as_bytes().into(),
1067        }
1068    }
1069    /// Construct a new resolve message to do a reverse lookup on an address
1070    pub fn new_reverse(addr: &IpAddr) -> Self {
1071        let query = match addr {
1072            IpAddr::V4(v4) => {
1073                let [a, b, c, d] = v4.octets();
1074                format!("{}.{}.{}.{}.in-addr.arpa", d, c, b, a)
1075            }
1076            IpAddr::V6(v6) => {
1077                let mut s = String::with_capacity(72);
1078                for o in v6.octets().iter().rev() {
1079                    let high_nybble = o >> 4;
1080                    let low_nybble = o & 15;
1081                    write!(s, "{:x}.{:x}.", low_nybble, high_nybble)
1082                        .expect("write to string failed");
1083                }
1084                write!(s, "ip6.arpa").expect("write to string failed");
1085                s
1086            }
1087        };
1088        Resolve {
1089            query: query.into_bytes(),
1090        }
1091    }
1092}
1093impl Body for Resolve {
1094    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
1095        let query = r.take_until(0)?;
1096        Ok(Resolve {
1097            query: query.into(),
1098        })
1099    }
1100    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
1101        w.write_all(&self.query[..]);
1102        w.write_u8(0);
1103        Ok(())
1104    }
1105}
1106
1107/// Possible response to a DNS lookup
1108#[derive(Debug, Clone, Eq, PartialEq, Deftly)]
1109#[derive_deftly(HasMemoryCost)]
1110#[non_exhaustive]
1111pub enum ResolvedVal {
1112    /// We found an IP address
1113    Ip(IpAddr),
1114    /// We found a hostname
1115    Hostname(Vec<u8>),
1116    /// Error; try again
1117    TransientError,
1118    /// Error; don't try again
1119    NontransientError,
1120    /// A DNS lookup response that we didn't recognize
1121    Unrecognized(u8, Vec<u8>),
1122}
1123
1124/// Indicates a hostname response
1125const RES_HOSTNAME: u8 = 0;
1126/// Indicates an IPv4 response
1127const RES_IPV4: u8 = 4;
1128/// Indicates an IPv6 response
1129const RES_IPV6: u8 = 6;
1130/// Transient error (okay to try again)
1131const RES_ERR_TRANSIENT: u8 = 0xF0;
1132/// Non-transient error (don't try again)
1133const RES_ERR_NONTRANSIENT: u8 = 0xF1;
1134
1135impl Readable for ResolvedVal {
1136    fn take_from(r: &mut Reader<'_>) -> Result<Self> {
1137        /// Helper: return the expected length of a resolved answer with
1138        /// a given type, if there is a particular expected length.
1139        fn res_len(tp: u8) -> Option<usize> {
1140            match tp {
1141                RES_IPV4 => Some(4),
1142                RES_IPV6 => Some(16),
1143                _ => None,
1144            }
1145        }
1146        let tp = r.take_u8()?;
1147        let len = r.take_u8()? as usize;
1148        if let Some(expected_len) = res_len(tp) {
1149            if len != expected_len {
1150                return Err(Error::InvalidMessage(
1151                    "Wrong length for RESOLVED answer".into(),
1152                ));
1153            }
1154        }
1155        Ok(match tp {
1156            RES_HOSTNAME => Self::Hostname(r.take(len)?.into()),
1157            RES_IPV4 => Self::Ip(IpAddr::V4(r.extract()?)),
1158            RES_IPV6 => Self::Ip(IpAddr::V6(r.extract()?)),
1159            RES_ERR_TRANSIENT => {
1160                r.advance(len)?;
1161                Self::TransientError
1162            }
1163            RES_ERR_NONTRANSIENT => {
1164                r.advance(len)?;
1165                Self::NontransientError
1166            }
1167            _ => Self::Unrecognized(tp, r.take(len)?.into()),
1168        })
1169    }
1170}
1171
1172impl Writeable for ResolvedVal {
1173    fn write_onto<B: Writer + ?Sized>(&self, w: &mut B) -> EncodeResult<()> {
1174        match self {
1175            Self::Hostname(h) => {
1176                w.write_u8(RES_HOSTNAME);
1177                let h_len: u8 = h
1178                    .len()
1179                    .try_into()
1180                    .map_err(|_| EncodeError::BadLengthValue)?;
1181                w.write_u8(h_len);
1182                w.write_all(&h[..]);
1183            }
1184            Self::Ip(IpAddr::V4(a)) => {
1185                w.write_u8(RES_IPV4);
1186                w.write_u8(4); // length
1187                w.write(a)?;
1188            }
1189            Self::Ip(IpAddr::V6(a)) => {
1190                w.write_u8(RES_IPV6);
1191                w.write_u8(16); // length
1192                w.write(a)?;
1193            }
1194            Self::TransientError => {
1195                w.write_u8(RES_ERR_TRANSIENT);
1196                w.write_u8(0); // length
1197            }
1198            Self::NontransientError => {
1199                w.write_u8(RES_ERR_NONTRANSIENT);
1200                w.write_u8(0); // length
1201            }
1202            Self::Unrecognized(tp, v) => {
1203                w.write_u8(*tp);
1204                let v_len: u8 = v
1205                    .len()
1206                    .try_into()
1207                    .map_err(|_| EncodeError::BadLengthValue)?;
1208                w.write_u8(v_len);
1209                w.write_all(&v[..]);
1210            }
1211        }
1212        Ok(())
1213    }
1214}
1215
1216/// A Resolved message is a successful reply to a Resolve message.
1217///
1218/// The Resolved message contains a list of zero or more addresses,
1219/// and their associated times-to-live in seconds.
1220#[derive(Debug, Clone, Deftly)]
1221#[derive_deftly(HasMemoryCost)]
1222pub struct Resolved {
1223    /// List of addresses and their associated time-to-live values.
1224    answers: Vec<(ResolvedVal, u32)>,
1225}
1226impl Resolved {
1227    /// Return a new empty Resolved object with no answers.
1228    pub fn new_empty() -> Self {
1229        Resolved {
1230            answers: Vec::new(),
1231        }
1232    }
1233    /// Return a new Resolved object reporting a name lookup error.
1234    ///
1235    /// TODO: Is getting no answer an error; or it is represented by
1236    /// a list of no answers?
1237    pub fn new_err(transient: bool, ttl: u32) -> Self {
1238        let mut res = Self::new_empty();
1239        let err = if transient {
1240            ResolvedVal::TransientError
1241        } else {
1242            ResolvedVal::NontransientError
1243        };
1244        res.add_answer(err, ttl);
1245        res
1246    }
1247    /// Add a single answer to this Resolved message
1248    pub fn add_answer(&mut self, answer: ResolvedVal, ttl: u32) {
1249        self.answers.push((answer, ttl));
1250    }
1251
1252    /// Consume this Resolved message, returning a vector of the
1253    /// answers and TTL values that it contains.
1254    ///
1255    /// Note that actually relying on these TTL values can be
1256    /// dangerous in practice, since the relay that sent the cell
1257    /// could be lying in order to cause more lookups, or to get a
1258    /// false answer cached for longer.
1259    pub fn into_answers(self) -> Vec<(ResolvedVal, u32)> {
1260        self.answers
1261    }
1262}
1263impl Body for Resolved {
1264    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
1265        let mut answers = Vec::new();
1266        while r.remaining() > 0 {
1267            let rv = r.extract()?;
1268            let ttl = r.take_u32()?;
1269            answers.push((rv, ttl));
1270        }
1271        Ok(Resolved { answers })
1272    }
1273    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
1274        for (rv, ttl) in &self.answers {
1275            w.write(rv)?;
1276            w.write_u32(*ttl);
1277        }
1278        Ok(())
1279    }
1280}
1281
1282/// A relay message that we didn't recognize
1283///
1284/// NOTE: Clients should generally reject these.
1285#[derive(Debug, Clone, Deftly)]
1286#[derive_deftly(HasMemoryCost)]
1287pub struct Unrecognized {
1288    /// Command that we didn't recognize
1289    cmd: RelayCmd,
1290    /// Body associated with that command
1291    body: Vec<u8>,
1292}
1293
1294impl Unrecognized {
1295    /// Create a new 'unrecognized' cell.
1296    pub fn new<B>(cmd: RelayCmd, body: B) -> Self
1297    where
1298        B: Into<Vec<u8>>,
1299    {
1300        let body = body.into();
1301        Unrecognized { cmd, body }
1302    }
1303
1304    /// Return the command associated with this message
1305    pub fn cmd(&self) -> RelayCmd {
1306        self.cmd
1307    }
1308    /// Decode this message, using a provided command.
1309    pub fn decode_with_cmd(cmd: RelayCmd, r: &mut Reader<'_>) -> Result<Self> {
1310        let mut r = Unrecognized::decode_from_reader(r)?;
1311        r.cmd = cmd;
1312        Ok(r)
1313    }
1314}
1315
1316impl Body for Unrecognized {
1317    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
1318        Ok(Unrecognized {
1319            cmd: 0.into(),
1320            body: r.take(r.remaining())?.into(),
1321        })
1322    }
1323    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
1324        w.write_all(&self.body[..]);
1325        Ok(())
1326    }
1327}
1328
1329/// Declare a message type for a message with an empty body.
1330macro_rules! empty_body {
1331   {
1332       $(#[$meta:meta])*
1333       pub struct $name:ident {}
1334   } => {
1335       $(#[$meta])*
1336       #[derive(Clone,Debug,Default,derive_deftly::Deftly)]
1337       #[derive_deftly(tor_memquota::HasMemoryCost)]
1338       #[non_exhaustive]
1339       pub struct $name {}
1340       impl $crate::relaycell::msg::Body for $name {
1341           fn decode_from_reader(_r: &mut Reader<'_>) -> Result<Self> {
1342               Ok(Self::default())
1343           }
1344           fn encode_onto<W: Writer + ?Sized>(self, _w: &mut W) -> EncodeResult<()> {
1345               Ok(())
1346           }
1347       }
1348   }
1349}
1350pub(crate) use empty_body;
1351
1352empty_body! {
1353    /// A padding message, which is always ignored.
1354    pub struct Drop {}
1355}
1356empty_body! {
1357    /// Tells a circuit to close all downstream hops on the circuit.
1358    pub struct Truncate {}
1359}
1360empty_body! {
1361    /// Opens a new stream on a directory cache.
1362    pub struct BeginDir {}
1363}
1364
1365/// Helper: declare a RelayMsg implementation for a message type that has a
1366/// fixed command.
1367//
1368// TODO: It might be better to merge Body with RelayMsg, but that is complex,
1369// since their needs are _slightly_ different.
1370//
1371// TODO: If we *do* make the change above, then perhaps we should also implement
1372// our restricted enums in terms of this, so that there is only one instance of
1373// [<$body:snake:upper>]
1374macro_rules! msg_impl_relaymsg {
1375    ($($body:ident),* $(,)?) =>
1376    {paste::paste!{
1377       $(impl crate::relaycell::RelayMsg for $body {
1378            fn cmd(&self) -> crate::relaycell::RelayCmd { crate::relaycell::RelayCmd::[< $body:snake:upper >] }
1379            fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()> {
1380                crate::relaycell::msg::Body::encode_onto(self, w)
1381            }
1382            fn decode_from_reader(cmd: RelayCmd, r: &mut tor_bytes::Reader<'_>) -> tor_bytes::Result<Self> {
1383                if cmd != crate::relaycell::RelayCmd::[< $body:snake:upper >] {
1384                    return Err(tor_bytes::Error::InvalidMessage(
1385                        format!("Expected {} command; got {cmd}", stringify!([< $body:snake:upper >])).into()
1386                    ));
1387                }
1388                crate::relaycell::msg::Body::decode_from_reader(r)
1389            }
1390        }
1391
1392        impl TryFrom<AnyRelayMsg> for $body {
1393            type Error = crate::Error;
1394            fn try_from(msg: AnyRelayMsg) -> crate::Result<$body> {
1395                use crate::relaycell::RelayMsg;
1396                match msg {
1397                    AnyRelayMsg::$body(b) => Ok(b),
1398                    _ => Err(crate::Error::CircProto(format!("Expected {}; got {}" ,
1399                                                     stringify!([<$body:snake:upper>]),
1400                                                     msg.cmd())) ),
1401                }
1402            }
1403        }
1404        )*
1405    }}
1406}
1407
1408msg_impl_relaymsg!(
1409    Begin, Data, End, Connected, Sendme, Extend, Extended, Extend2, Extended2, Truncate, Truncated,
1410    Drop, Resolve, Resolved, BeginDir,
1411);
1412
1413#[cfg(feature = "experimental-udp")]
1414msg_impl_relaymsg!(ConnectUdp, ConnectedUdp, Datagram);
1415
1416#[cfg(feature = "hs")]
1417msg_impl_relaymsg!(
1418    EstablishIntro,
1419    EstablishRendezvous,
1420    Introduce1,
1421    Introduce2,
1422    Rendezvous1,
1423    Rendezvous2,
1424    IntroEstablished,
1425    RendezvousEstablished,
1426    IntroduceAck,
1427);
1428
1429#[cfg(feature = "conflux")]
1430msg_impl_relaymsg!(ConfluxSwitch, ConfluxLink, ConfluxLinked, ConfluxLinkedAck);
1431
1432msg_impl_relaymsg!(Xon, Xoff);
1433
1434#[cfg(test)]
1435mod test {
1436    // @@ begin test lint list maintained by maint/add_warning @@
1437    #![allow(clippy::bool_assert_comparison)]
1438    #![allow(clippy::clone_on_copy)]
1439    #![allow(clippy::dbg_macro)]
1440    #![allow(clippy::mixed_attributes_style)]
1441    #![allow(clippy::print_stderr)]
1442    #![allow(clippy::print_stdout)]
1443    #![allow(clippy::single_char_pattern)]
1444    #![allow(clippy::unwrap_used)]
1445    #![allow(clippy::unchecked_duration_subtraction)]
1446    #![allow(clippy::useless_vec)]
1447    #![allow(clippy::needless_pass_by_value)]
1448    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
1449
1450    use super::*;
1451
1452    #[test]
1453    fn sendme_tags() {
1454        // strings of 20 or 16 bytes.
1455        let ts: Vec<SendmeTag> = vec![
1456            (*b"Yea, on the word of ").into(),
1457            (*b"a Bloom, ye shal").into(),
1458            (*b"l ere long enter int").into(),
1459            (*b"o the golden cit").into(),
1460        ];
1461
1462        for (i1, i2) in (0..4).zip(0..4) {
1463            if i1 == i2 {
1464                assert_eq!(ts[i1], ts[i2]);
1465            } else {
1466                assert_ne!(ts[i1], ts[i2]);
1467            }
1468        }
1469
1470        assert_eq!(ts[0].as_ref(), &b"Yea, on the word of "[..]);
1471        assert_eq!(ts[3].as_ref(), &b"o the golden cit"[..]);
1472
1473        assert_eq!(ts[1], b"a Bloom, ye shal"[..].try_into().unwrap());
1474        assert_eq!(ts[2], b"l ere long enter int"[..].try_into().unwrap());
1475
1476        // 15 bytes long.
1477        assert!(matches!(
1478            SendmeTag::try_from(&b"o the golden ci"[..]),
1479            Err(InvalidSendmeTag { .. }),
1480        ));
1481    }
1482}