Skip to main content

tor_cell/relaycell/
msg.rs

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