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