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