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}