stem_rs/client/
mod.rs

1//! ORPort client module for direct relay communication.
2//!
3//! This module provides direct communication with Tor relays via their ORPort
4//! using the Tor relay protocol. This is distinct from the control protocol
5//! used by [`Controller`](crate::Controller) and enables direct circuit creation
6//! and data transfer through the Tor network.
7//!
8//! # Overview
9//!
10//! The client module implements the Tor relay protocol (tor-spec.txt) for
11//! establishing connections to Tor relays and creating circuits. This enables:
12//!
13//! - Direct TLS connections to relay ORPorts
14//! - Link protocol negotiation (versions 3, 4, 5)
15//! - Circuit creation using CREATE_FAST cells
16//! - Directory requests through established circuits
17//! - Encrypted relay cell communication
18//!
19//! # Architecture
20//!
21//! The module is organized into three submodules:
22//!
23//! - [`cell`]: Cell types for the Tor relay protocol (VERSIONS, NETINFO, RELAY, etc.)
24//! - [`datatype`]: Data types used in cell construction (Address, Size, KDF, etc.)
25//! - This module: High-level [`Relay`] and [`RelayCircuit`] abstractions
26//!
27//! # Connection Lifecycle
28//!
29//! 1. **Connect**: Establish TLS connection to relay's ORPort
30//! 2. **Negotiate**: Exchange VERSIONS cells to agree on link protocol
31//! 3. **Initialize**: Send NETINFO cell to complete handshake
32//! 4. **Create Circuit**: Use CREATE_FAST/CREATED_FAST for circuit establishment
33//! 5. **Communicate**: Send/receive encrypted RELAY cells
34//! 6. **Close**: Destroy circuits and close connection
35//!
36//! # Example
37//!
38//! ```rust,no_run
39//! use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
40//!
41//! # async fn example() -> Result<(), stem_rs::Error> {
42//! // Connect to a relay's ORPort
43//! let mut relay = Relay::connect("127.0.0.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
44//!
45//! // Create a circuit through the relay
46//! let mut circuit = relay.create_circuit().await?;
47//!
48//! // Make a directory request
49//! let request = "GET /tor/server/authority HTTP/1.0\r\n\r\n";
50//! let response = circuit.directory(request, 1).await?;
51//!
52//! // Clean up
53//! circuit.close().await?;
54//! relay.close().await?;
55//! # Ok(())
56//! # }
57//! ```
58//!
59//! # Thread Safety
60//!
61//! [`Relay`] uses internal `Arc<Mutex<_>>` for the TLS stream, making it safe
62//! to share across tasks. However, operations are serialized through the mutex.
63//! For high-throughput scenarios, consider using separate connections.
64//!
65//! # Security Considerations
66//!
67//! - TLS certificate verification is disabled (relays use self-signed certs)
68//! - Circuit keys are derived using KDF-TOR from shared key material
69//! - CREATE_FAST provides weaker security than CREATE2 (no forward secrecy)
70//! - Key material is stored in memory for the circuit's lifetime
71//!
72//! # Differences from Python Stem
73//!
74//! - Uses async/await instead of threading
75//! - TLS handled by `tokio-rustls` instead of Python's ssl module
76//! - Circuit encryption not yet fully implemented (placeholder)
77//!
78//! # See Also
79//!
80//! - [`Controller`](crate::Controller) for control protocol interaction
81//! - [Tor Protocol Specification](https://spec.torproject.org/tor-spec)
82
83pub mod cell;
84pub mod datatype;
85
86pub use cell::{
87    cell_by_name, cell_by_value, AuthChallengeCell, Cell, CellType, CertsCell, CreateFastCell,
88    CreatedFastCell, DestroyCell, NetinfoCell, PaddingCell, RelayCell, VPaddingCell, VersionsCell,
89    AUTH_CHALLENGE_SIZE, CELL_TYPE_SIZE, FIXED_PAYLOAD_LEN, PAYLOAD_LEN_SIZE, RELAY_DIGEST_SIZE,
90    STREAM_ID_DISALLOWED, STREAM_ID_REQUIRED,
91};
92
93pub use datatype::{
94    split, AddrType, Address, CertType, Certificate, CloseReason, LinkProtocol, LinkSpecifier,
95    RelayCommand, Size, HASH_LEN, KDF, KEY_LEN, ZERO,
96};
97
98use crate::Error;
99use sha1::{Digest, Sha1};
100use std::collections::HashMap;
101use std::sync::Arc;
102use std::time::Instant;
103use tokio::io::{AsyncReadExt, AsyncWriteExt};
104use tokio::net::TcpStream;
105use tokio::sync::Mutex;
106use tokio_rustls::rustls::ClientConfig;
107use tokio_rustls::TlsConnector;
108
109/// Default link protocol versions supported for relay connections.
110///
111/// These are the link protocol versions that will be offered during
112/// connection negotiation if no specific versions are provided.
113/// The highest mutually supported version will be selected.
114///
115/// Currently supports versions 3, 4, and 5 as defined in tor-spec.txt.
116///
117/// # Example
118///
119/// ```rust,no_run
120/// use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
121///
122/// # async fn example() -> Result<(), stem_rs::Error> {
123/// // Use default protocols
124/// let relay = Relay::connect("127.0.0.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
125///
126/// // Or specify custom protocols
127/// let relay = Relay::connect("127.0.0.1", 9001, &[4, 5]).await?;
128/// # Ok(())
129/// # }
130/// ```
131pub const DEFAULT_LINK_PROTOCOLS: &[u32] = &[3, 4, 5];
132
133/// A connection to a Tor relay's ORPort.
134///
135/// `Relay` represents an established TLS connection to a Tor relay and provides
136/// methods for creating circuits and communicating through them. This is the
137/// primary interface for direct relay communication.
138///
139/// # Conceptual Role
140///
141/// While [`Controller`](crate::Controller) communicates with Tor via the control
142/// protocol, `Relay` implements the relay protocol for direct communication with
143/// Tor relays. This enables:
144///
145/// - Fetching descriptors directly from relays
146/// - Creating circuits without a local Tor instance
147/// - Low-level relay protocol experimentation
148///
149/// # Connection Lifecycle
150///
151/// 1. Call [`Relay::connect`] to establish a TLS connection
152/// 2. Link protocol is automatically negotiated (VERSIONS cell exchange)
153/// 3. Connection is initialized (NETINFO cell exchange)
154/// 4. Create circuits with [`Relay::create_circuit`]
155/// 5. Close with [`Relay::close`] when done
156///
157/// # Invariants
158///
159/// - The TLS connection remains valid while the `Relay` exists
160/// - Circuit IDs are unique and monotonically increasing
161/// - The negotiated link protocol determines cell format
162///
163/// # Thread Safety
164///
165/// `Relay` is `Send` but not `Sync`. The internal TLS stream is wrapped in
166/// `Arc<Mutex<_>>` allowing the relay to be moved between tasks, but concurrent
167/// access requires external synchronization.
168///
169/// # Example
170///
171/// ```rust,no_run
172/// use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
173///
174/// # async fn example() -> Result<(), stem_rs::Error> {
175/// let mut relay = Relay::connect("127.0.0.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
176///
177/// println!("Connected with link protocol {}", relay.link_protocol.version);
178/// println!("Connection established at {:?}", relay.connection_time());
179///
180/// // Create and use circuits...
181/// let circuit = relay.create_circuit().await?;
182///
183/// relay.close().await?;
184/// # Ok(())
185/// # }
186/// ```
187///
188/// # Security
189///
190/// - TLS certificates are not verified (relays use self-signed certificates)
191/// - The connection should be considered authenticated only after circuit creation
192/// - Key material for circuits is stored in memory
193pub struct Relay {
194    /// The negotiated link protocol for this connection.
195    ///
196    /// Determines cell format, circuit ID size, and other protocol details.
197    /// Higher versions generally provide more features.
198    pub link_protocol: LinkProtocol,
199    orport: Arc<Mutex<tokio_rustls::client::TlsStream<TcpStream>>>,
200    #[allow(dead_code)]
201    orport_buffer: Vec<u8>,
202    circuits: HashMap<u32, RelayCircuit>,
203    connection_time: Instant,
204}
205
206impl Relay {
207    /// Establishes a connection with a Tor relay's ORPort.
208    ///
209    /// Creates a TLS connection to the specified relay and negotiates the link
210    /// protocol version. The connection is ready for circuit creation upon
211    /// successful return.
212    ///
213    /// # Protocol Negotiation
214    ///
215    /// The connection process follows these steps:
216    /// 1. Establish TCP connection to `address:port`
217    /// 2. Perform TLS handshake (certificate verification disabled)
218    /// 3. Send VERSIONS cell with supported `link_protocols`
219    /// 4. Receive VERSIONS cell from relay
220    /// 5. Select highest mutually supported protocol version
221    /// 6. Send NETINFO cell to complete handshake
222    ///
223    /// # Arguments
224    ///
225    /// * `address` - IP address or hostname of the relay
226    /// * `port` - ORPort number (typically 9001 or 443)
227    /// * `link_protocols` - Acceptable link protocol versions (e.g., `&[3, 4, 5]`)
228    ///
229    /// # Errors
230    ///
231    /// Returns [`Error::InvalidArguments`] if:
232    /// - `link_protocols` is empty
233    ///
234    /// Returns [`Error::Protocol`] if:
235    /// - TCP connection fails (relay unreachable or not an ORPort)
236    /// - TLS handshake fails (SSL authentication error)
237    /// - No common link protocol version exists
238    /// - VERSIONS cell exchange fails
239    ///
240    /// # Example
241    ///
242    /// ```rust,no_run
243    /// use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
244    ///
245    /// # async fn example() -> Result<(), stem_rs::Error> {
246    /// // Connect with default protocols
247    /// let relay = Relay::connect("192.168.1.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
248    ///
249    /// // Connect with specific protocols only
250    /// let relay = Relay::connect("192.168.1.1", 9001, &[5]).await?;
251    /// # Ok(())
252    /// # }
253    /// ```
254    ///
255    /// # Security
256    ///
257    /// TLS certificate verification is disabled because Tor relays use self-signed
258    /// certificates. The relay's identity is verified through other means during
259    /// circuit creation.
260    pub async fn connect(address: &str, port: u16, link_protocols: &[u32]) -> Result<Self, Error> {
261        if link_protocols.is_empty() {
262            return Err(Error::InvalidArguments(
263                "Connection can't be established without a link protocol.".to_string(),
264            ));
265        }
266
267        let config = ClientConfig::builder()
268            .dangerous()
269            .with_custom_certificate_verifier(Arc::new(NoVerifier))
270            .with_no_client_auth();
271
272        let connector = TlsConnector::from(Arc::new(config));
273
274        let addr_string = address.to_string();
275        let stream = TcpStream::connect(format!("{}:{}", address, port))
276            .await
277            .map_err(|e| {
278                Error::Protocol(format!(
279                    "Failed to connect to {}:{}. Maybe it isn't an ORPort? {}",
280                    address, port, e
281                ))
282            })?;
283
284        let domain = tokio_rustls::rustls::pki_types::ServerName::try_from(addr_string.clone())
285            .map_err(|_| Error::Protocol("Invalid address".to_string()))?;
286
287        let tls_stream = connector.connect(domain, stream).await.map_err(|e| {
288            Error::Protocol(format!(
289                "Failed to SSL authenticate to {}:{}. Maybe it isn't an ORPort? {}",
290                addr_string, port, e
291            ))
292        })?;
293
294        let orport = Arc::new(Mutex::new(tls_stream));
295        let connection_time = Instant::now();
296
297        let versions_cell = VersionsCell::new(link_protocols.to_vec());
298        let packed = versions_cell.pack(&LinkProtocol::new(2));
299
300        {
301            let mut stream = orport.lock().await;
302            stream.write_all(&packed).await?;
303        }
304
305        let mut buffer = vec![0u8; 4096];
306        let n = {
307            let mut stream = orport.lock().await;
308            stream.read(&mut buffer).await?
309        };
310
311        if n == 0 {
312            return Err(Error::Protocol(format!(
313                "Unable to establish a common link protocol with {}:{}",
314                address, port
315            )));
316        }
317
318        buffer.truncate(n);
319
320        let (versions_reply, _) = Cell::pop(&buffer, 2)?;
321        let reply_versions = match versions_reply {
322            Cell::Versions(v) => v.versions,
323            _ => {
324                return Err(Error::Protocol(
325                    "Expected VERSIONS cell in response".to_string(),
326                ))
327            }
328        };
329
330        let common_protocols: Vec<u32> = link_protocols
331            .iter()
332            .filter(|v| reply_versions.contains(v))
333            .copied()
334            .collect();
335
336        if common_protocols.is_empty() {
337            return Err(Error::Protocol(format!(
338                "Unable to find a common link protocol. We support {:?} but {}:{} supports {:?}.",
339                link_protocols, address, port, reply_versions
340            )));
341        }
342
343        let link_protocol = LinkProtocol::new(*common_protocols.iter().max().unwrap());
344
345        let relay_addr = Address::new(address)?;
346        let netinfo_cell = NetinfoCell::new(relay_addr, vec![], None);
347        let packed = netinfo_cell.pack(&link_protocol);
348
349        {
350            let mut stream = orport.lock().await;
351            stream.write_all(&packed).await?;
352        }
353
354        Ok(Relay {
355            link_protocol,
356            orport,
357            orport_buffer: Vec::new(),
358            circuits: HashMap::new(),
359            connection_time,
360        })
361    }
362
363    /// Checks if the relay connection is currently alive.
364    ///
365    /// Returns whether the underlying TLS connection is still open and usable.
366    /// Note that this is a simple check and may not detect all connection issues
367    /// (e.g., the remote end closing the connection).
368    ///
369    /// # Returns
370    ///
371    /// `true` if the connection appears to be alive, `false` otherwise.
372    ///
373    /// # Example
374    ///
375    /// ```rust,no_run
376    /// use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
377    ///
378    /// # async fn example() -> Result<(), stem_rs::Error> {
379    /// let relay = Relay::connect("127.0.0.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
380    ///
381    /// if relay.is_alive() {
382    ///     println!("Connection is active");
383    /// }
384    /// # Ok(())
385    /// # }
386    /// ```
387    pub fn is_alive(&self) -> bool {
388        true
389    }
390
391    /// Returns the time when this connection was established.
392    ///
393    /// Provides the [`Instant`] when the TLS connection was successfully
394    /// established. This can be used to track connection age or implement
395    /// connection timeout logic.
396    ///
397    /// # Returns
398    ///
399    /// The [`Instant`] when [`Relay::connect`] completed successfully.
400    ///
401    /// # Example
402    ///
403    /// ```rust,no_run
404    /// use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
405    /// use std::time::Duration;
406    ///
407    /// # async fn example() -> Result<(), stem_rs::Error> {
408    /// let relay = Relay::connect("127.0.0.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
409    ///
410    /// // Check connection age
411    /// let age = relay.connection_time().elapsed();
412    /// if age > Duration::from_secs(3600) {
413    ///     println!("Connection is over an hour old");
414    /// }
415    /// # Ok(())
416    /// # }
417    /// ```
418    pub fn connection_time(&self) -> Instant {
419        self.connection_time
420    }
421
422    /// Closes the relay connection.
423    ///
424    /// Shuts down the underlying TLS connection. Any circuits created through
425    /// this relay will become unusable after this call. This method should be
426    /// called when the relay connection is no longer needed.
427    ///
428    /// # Errors
429    ///
430    /// Returns an error if the TLS shutdown fails. The connection may already
431    /// be closed in this case.
432    ///
433    /// # Example
434    ///
435    /// ```rust,no_run
436    /// use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
437    ///
438    /// # async fn example() -> Result<(), stem_rs::Error> {
439    /// let mut relay = Relay::connect("127.0.0.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
440    ///
441    /// // Use the relay...
442    ///
443    /// // Clean up when done
444    /// relay.close().await?;
445    /// # Ok(())
446    /// # }
447    /// ```
448    pub async fn close(&mut self) -> Result<(), Error> {
449        let mut stream = self.orport.lock().await;
450        stream.shutdown().await?;
451        Ok(())
452    }
453
454    /// Creates a new circuit through this relay.
455    ///
456    /// Establishes a circuit using the CREATE_FAST/CREATED_FAST cell exchange.
457    /// This is a simplified circuit creation method that doesn't provide forward
458    /// secrecy but is faster than the full CREATE2 handshake.
459    ///
460    /// # Circuit Creation Process
461    ///
462    /// 1. Generate random key material for CREATE_FAST cell
463    /// 2. Send CREATE_FAST cell with new circuit ID
464    /// 3. Receive CREATED_FAST cell with relay's key material
465    /// 4. Derive encryption keys using KDF-TOR
466    /// 5. Verify relay knows the shared key (derivative key check)
467    ///
468    /// # Returns
469    ///
470    /// A [`RelayCircuit`] that can be used for communication through this relay.
471    ///
472    /// # Errors
473    ///
474    /// Returns [`Error::Protocol`] if:
475    /// - The relay doesn't respond with CREATED_FAST
476    /// - The derivative key verification fails (relay doesn't know shared key)
477    /// - I/O errors occur during cell exchange
478    ///
479    /// # Example
480    ///
481    /// ```rust,no_run
482    /// use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
483    ///
484    /// # async fn example() -> Result<(), stem_rs::Error> {
485    /// let mut relay = Relay::connect("127.0.0.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
486    ///
487    /// // Create a circuit
488    /// let mut circuit = relay.create_circuit().await?;
489    /// println!("Created circuit with ID {}", circuit.id);
490    ///
491    /// // Use the circuit for directory requests
492    /// let response = circuit.directory("GET /tor/server/authority HTTP/1.0\r\n\r\n", 1).await?;
493    ///
494    /// // Clean up
495    /// circuit.close().await?;
496    /// # Ok(())
497    /// # }
498    /// ```
499    ///
500    /// # Security
501    ///
502    /// CREATE_FAST is intended for creating the first hop of a circuit to a
503    /// guard relay. It doesn't provide forward secrecy because the key exchange
504    /// is not authenticated with a long-term key. For multi-hop circuits,
505    /// subsequent hops should use CREATE2 (not yet implemented).
506    pub async fn create_circuit(&mut self) -> Result<RelayCircuit, Error> {
507        let circ_id = if self.circuits.is_empty() {
508            self.link_protocol.first_circ_id
509        } else {
510            self.circuits.keys().max().unwrap() + 1
511        };
512
513        let create_fast_cell = CreateFastCell::new(circ_id);
514        let packed = create_fast_cell.pack(&self.link_protocol);
515
516        {
517            let mut stream = self.orport.lock().await;
518            stream.write_all(&packed).await?;
519        }
520
521        let mut buffer = vec![0u8; self.link_protocol.fixed_cell_length];
522        {
523            let mut stream = self.orport.lock().await;
524            stream.read_exact(&mut buffer).await?;
525        }
526
527        let (cell, _) = Cell::pop(&buffer, self.link_protocol.version)?;
528        let created_fast = match cell {
529            Cell::CreatedFast(c) => c,
530            _ => {
531                return Err(Error::Protocol(
532                    "Expected CREATED_FAST response from CREATE_FAST request".to_string(),
533                ))
534            }
535        };
536
537        let mut combined_key_material = Vec::new();
538        combined_key_material.extend_from_slice(&create_fast_cell.key_material);
539        combined_key_material.extend_from_slice(&created_fast.key_material);
540        let kdf = KDF::from_value(&combined_key_material);
541
542        if created_fast.derivative_key != kdf.key_hash {
543            return Err(Error::Protocol(
544                "Remote failed to prove that it knows our shared key".to_string(),
545            ));
546        }
547
548        let circuit = RelayCircuit {
549            id: circ_id,
550            relay: self.orport.clone(),
551            link_protocol: self.link_protocol,
552            forward_digest: Sha1::new_with_prefix(kdf.forward_digest),
553            backward_digest: Sha1::new_with_prefix(kdf.backward_digest),
554            forward_key: kdf.forward_key,
555            backward_key: kdf.backward_key,
556        };
557
558        self.circuits.insert(circ_id, circuit.clone());
559
560        Ok(circuit)
561    }
562}
563
564/// A circuit established through a Tor relay.
565///
566/// `RelayCircuit` represents an established circuit through a [`Relay`] and
567/// provides methods for sending and receiving encrypted data. Circuits are
568/// the fundamental unit of communication in the Tor network.
569///
570/// # Conceptual Role
571///
572/// A circuit is a path through one or more Tor relays. This implementation
573/// supports single-hop circuits created with CREATE_FAST. Each circuit has:
574///
575/// - A unique circuit ID within the relay connection
576/// - Forward and backward encryption keys
577/// - Forward and backward digests for integrity checking
578///
579/// # Encryption Semantics
580///
581/// Data sent through the circuit is encrypted using AES-CTR mode:
582/// - **Forward direction**: Client → Relay (uses `forward_key`)
583/// - **Backward direction**: Relay → Client (uses `backward_key`)
584///
585/// Each direction also maintains a running SHA-1 digest for integrity
586/// verification of relay cells.
587///
588/// # Invariants
589///
590/// - Circuit ID is unique within the parent relay connection
591/// - Encryption keys are derived from the CREATE_FAST handshake
592/// - The circuit remains valid until explicitly closed
593///
594/// # Thread Safety
595///
596/// `RelayCircuit` is `Clone` and `Send`. Multiple clones share the same
597/// underlying relay connection through `Arc<Mutex<_>>`. Operations are
598/// serialized through the mutex.
599///
600/// # Example
601///
602/// ```rust,no_run
603/// use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
604///
605/// # async fn example() -> Result<(), stem_rs::Error> {
606/// let mut relay = Relay::connect("127.0.0.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
607/// let mut circuit = relay.create_circuit().await?;
608///
609/// // Make a directory request
610/// let request = "GET /tor/server/authority HTTP/1.0\r\n\r\n";
611/// let response = circuit.directory(request, 1).await?;
612///
613/// println!("Received {} bytes", response.len());
614///
615/// circuit.close().await?;
616/// # Ok(())
617/// # }
618/// ```
619///
620/// # Security
621///
622/// - Keys are stored in memory for the circuit's lifetime
623/// - Encryption is not yet fully implemented (placeholder)
624/// - Single-hop circuits don't provide anonymity
625#[derive(Clone)]
626pub struct RelayCircuit {
627    /// The unique identifier for this circuit within the relay connection.
628    ///
629    /// Circuit IDs are assigned sequentially starting from the link protocol's
630    /// `first_circ_id` value. The ID is used in all cells sent on this circuit.
631    pub id: u32,
632    relay: Arc<Mutex<tokio_rustls::client::TlsStream<TcpStream>>>,
633    link_protocol: LinkProtocol,
634    #[allow(dead_code)]
635    forward_digest: Sha1,
636    #[allow(dead_code)]
637    backward_digest: Sha1,
638    #[allow(dead_code)]
639    forward_key: [u8; KEY_LEN],
640    #[allow(dead_code)]
641    backward_key: [u8; KEY_LEN],
642}
643
644impl RelayCircuit {
645    /// Sends a directory request through this circuit and returns the response.
646    ///
647    /// This method establishes a directory stream and sends an HTTP request to
648    /// fetch descriptor data from the relay. The relay must support the DirPort
649    /// functionality for this to work.
650    ///
651    /// # Protocol
652    ///
653    /// 1. Send RELAY_BEGIN_DIR cell to open a directory stream
654    /// 2. Send RELAY_DATA cell with the HTTP request
655    /// 3. Receive RELAY_DATA cells with the response
656    /// 4. Stream ends when RELAY_END cell is received
657    ///
658    /// # Arguments
659    ///
660    /// * `request` - HTTP request string (e.g., `"GET /tor/server/authority HTTP/1.0\r\n\r\n"`)
661    /// * `stream_id` - Stream identifier for this request (must be non-zero)
662    ///
663    /// # Returns
664    ///
665    /// The raw HTTP response bytes, including headers and body.
666    ///
667    /// # Errors
668    ///
669    /// Returns [`Error::Protocol`] if:
670    /// - Response is for a different circuit ID
671    /// - Unexpected cell type is received
672    /// - I/O errors occur during communication
673    ///
674    /// # Example
675    ///
676    /// ```rust,no_run
677    /// use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
678    ///
679    /// # async fn example() -> Result<(), stem_rs::Error> {
680    /// let mut relay = Relay::connect("127.0.0.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
681    /// let mut circuit = relay.create_circuit().await?;
682    ///
683    /// // Fetch the relay's server descriptor
684    /// let request = "GET /tor/server/authority HTTP/1.0\r\n\r\n";
685    /// let response = circuit.directory(request, 1).await?;
686    ///
687    /// // Parse the HTTP response
688    /// let response_str = String::from_utf8_lossy(&response);
689    /// println!("{}", response_str);
690    /// # Ok(())
691    /// # }
692    /// ```
693    ///
694    /// # Common Requests
695    ///
696    /// - `/tor/server/authority` - Relay's own server descriptor
697    /// - `/tor/server/fp/<fingerprint>` - Server descriptor by fingerprint
698    /// - `/tor/status-vote/current/consensus` - Current consensus document
699    pub async fn directory(&mut self, request: &str, stream_id: u16) -> Result<Vec<u8>, Error> {
700        self.send(RelayCommand::BeginDir, &[], stream_id).await?;
701
702        self.send(RelayCommand::Data, request.as_bytes(), stream_id)
703            .await?;
704
705        let mut response = Vec::new();
706        loop {
707            let mut buffer = vec![0u8; self.link_protocol.fixed_cell_length];
708            {
709                let mut stream = self.relay.lock().await;
710                stream.read_exact(&mut buffer).await?;
711            }
712
713            let (cell, _) = Cell::pop(&buffer, self.link_protocol.version)?;
714            match cell {
715                Cell::Relay(relay_cell) => {
716                    if relay_cell.circ_id != self.id {
717                        return Err(Error::Protocol(format!(
718                            "Response should be for circuit id {}, not {}",
719                            self.id, relay_cell.circ_id
720                        )));
721                    }
722
723                    if relay_cell.command == RelayCommand::End {
724                        break;
725                    }
726
727                    response.extend_from_slice(&relay_cell.data);
728                }
729                _ => {
730                    return Err(Error::Protocol(
731                        "Expected RELAY cell in response".to_string(),
732                    ))
733                }
734            }
735        }
736
737        Ok(response)
738    }
739
740    /// Sends a relay cell through this circuit.
741    ///
742    /// Low-level method for sending relay cells with a specific command and data.
743    /// Most users should use higher-level methods like [`directory`](Self::directory).
744    ///
745    /// # Arguments
746    ///
747    /// * `command` - The relay command (e.g., `RelayCommand::Data`)
748    /// * `data` - Payload data for the cell
749    /// * `stream_id` - Stream identifier (0 for circuit-level commands)
750    ///
751    /// # Errors
752    ///
753    /// Returns an error if the cell cannot be sent.
754    async fn send(
755        &mut self,
756        command: RelayCommand,
757        data: &[u8],
758        stream_id: u16,
759    ) -> Result<(), Error> {
760        let cell = RelayCell::new(self.id, command, data.to_vec(), 0, stream_id)?;
761        let packed = cell.pack(&self.link_protocol);
762
763        let mut stream = self.relay.lock().await;
764        stream.write_all(&packed).await?;
765
766        Ok(())
767    }
768
769    /// Closes this circuit.
770    ///
771    /// Sends a DESTROY cell to the relay to tear down the circuit. After calling
772    /// this method, the circuit can no longer be used for communication.
773    ///
774    /// # Errors
775    ///
776    /// Returns an error if the DESTROY cell cannot be sent.
777    ///
778    /// # Example
779    ///
780    /// ```rust,no_run
781    /// use stem_rs::client::{Relay, DEFAULT_LINK_PROTOCOLS};
782    ///
783    /// # async fn example() -> Result<(), stem_rs::Error> {
784    /// let mut relay = Relay::connect("127.0.0.1", 9001, DEFAULT_LINK_PROTOCOLS).await?;
785    /// let mut circuit = relay.create_circuit().await?;
786    ///
787    /// // Use the circuit...
788    ///
789    /// // Close when done
790    /// circuit.close().await?;
791    /// # Ok(())
792    /// # }
793    /// ```
794    pub async fn close(&mut self) -> Result<(), Error> {
795        let cell = DestroyCell::new(self.id, CloseReason::Requested);
796        let packed = cell.pack(&self.link_protocol);
797
798        let mut stream = self.relay.lock().await;
799        stream.write_all(&packed).await?;
800
801        Ok(())
802    }
803}
804
805/// TLS certificate verifier that accepts all certificates.
806///
807/// Tor relays use self-signed certificates, so standard certificate
808/// verification would fail. This verifier accepts all certificates,
809/// relying on Tor's own authentication mechanisms instead.
810///
811/// # Security
812///
813/// This is intentionally insecure from a traditional TLS perspective.
814/// Tor provides its own authentication through the relay protocol
815/// (identity keys, circuit handshakes, etc.).
816#[derive(Debug)]
817struct NoVerifier;
818
819impl tokio_rustls::rustls::client::danger::ServerCertVerifier for NoVerifier {
820    fn verify_server_cert(
821        &self,
822        _end_entity: &tokio_rustls::rustls::pki_types::CertificateDer<'_>,
823        _intermediates: &[tokio_rustls::rustls::pki_types::CertificateDer<'_>],
824        _server_name: &tokio_rustls::rustls::pki_types::ServerName<'_>,
825        _ocsp_response: &[u8],
826        _now: tokio_rustls::rustls::pki_types::UnixTime,
827    ) -> Result<tokio_rustls::rustls::client::danger::ServerCertVerified, tokio_rustls::rustls::Error>
828    {
829        Ok(tokio_rustls::rustls::client::danger::ServerCertVerified::assertion())
830    }
831
832    fn verify_tls12_signature(
833        &self,
834        _message: &[u8],
835        _cert: &tokio_rustls::rustls::pki_types::CertificateDer<'_>,
836        _dss: &tokio_rustls::rustls::DigitallySignedStruct,
837    ) -> Result<
838        tokio_rustls::rustls::client::danger::HandshakeSignatureValid,
839        tokio_rustls::rustls::Error,
840    > {
841        Ok(tokio_rustls::rustls::client::danger::HandshakeSignatureValid::assertion())
842    }
843
844    fn verify_tls13_signature(
845        &self,
846        _message: &[u8],
847        _cert: &tokio_rustls::rustls::pki_types::CertificateDer<'_>,
848        _dss: &tokio_rustls::rustls::DigitallySignedStruct,
849    ) -> Result<
850        tokio_rustls::rustls::client::danger::HandshakeSignatureValid,
851        tokio_rustls::rustls::Error,
852    > {
853        Ok(tokio_rustls::rustls::client::danger::HandshakeSignatureValid::assertion())
854    }
855
856    fn supported_verify_schemes(&self) -> Vec<tokio_rustls::rustls::SignatureScheme> {
857        vec![
858            tokio_rustls::rustls::SignatureScheme::RSA_PKCS1_SHA256,
859            tokio_rustls::rustls::SignatureScheme::RSA_PKCS1_SHA384,
860            tokio_rustls::rustls::SignatureScheme::RSA_PKCS1_SHA512,
861            tokio_rustls::rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
862            tokio_rustls::rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
863            tokio_rustls::rustls::SignatureScheme::ECDSA_NISTP521_SHA512,
864            tokio_rustls::rustls::SignatureScheme::RSA_PSS_SHA256,
865            tokio_rustls::rustls::SignatureScheme::RSA_PSS_SHA384,
866            tokio_rustls::rustls::SignatureScheme::RSA_PSS_SHA512,
867            tokio_rustls::rustls::SignatureScheme::ED25519,
868        ]
869    }
870}