stem_rs/client/datatype.rs
1//! Data types for the Tor relay protocol.
2//!
3//! This module provides low-level data types used in ORPort communication
4//! with Tor relays. These types handle the binary encoding and decoding
5//! of protocol messages as defined in the
6//! [Tor specification](https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt).
7//!
8//! # Overview
9//!
10//! The module contains several categories of types:
11//!
12//! - **Size types**: [`Size`] for packing/unpacking integers of various widths
13//! - **Protocol versioning**: [`LinkProtocol`] for version-dependent constants
14//! - **Addressing**: [`Address`], [`AddrType`], and [`LinkSpecifier`] for relay addresses
15//! - **Certificates**: [`Certificate`] and [`CertType`] for relay certificates
16//! - **Commands**: [`RelayCommand`] and [`CloseReason`] for circuit operations
17//! - **Key derivation**: [`KDF`] for cryptographic key material
18//!
19//! # Conceptual Role
20//!
21//! These types form the foundation of the ORPort protocol implementation.
22//! They handle the serialization and deserialization of binary data according
23//! to Tor's wire format, which uses big-endian byte ordering throughout.
24//!
25//! Most users should interact with the higher-level [`Relay`](super::Relay)
26//! and [`RelayCircuit`](super::RelayCircuit) types rather than using these
27//! primitives directly.
28//!
29//! # Wire Format
30//!
31//! All multi-byte integers are encoded in network byte order (big-endian).
32//! Variable-length fields are typically prefixed with their length.
33//!
34//! # Example
35//!
36//! ```rust
37//! use stem_rs::client::datatype::{Size, Address, AddrType};
38//!
39//! // Pack and unpack integers
40//! let packed = Size::Short.pack(9001);
41//! assert_eq!(packed, vec![0x23, 0x29]);
42//!
43//! let unpacked = Size::Short.unpack(&packed).unwrap();
44//! assert_eq!(unpacked, 9001);
45//!
46//! // Parse an IPv4 address
47//! let addr = Address::new("127.0.0.1").unwrap();
48//! assert_eq!(addr.addr_type, AddrType::IPv4);
49//! ```
50//!
51//! # Security Considerations
52//!
53//! These types handle untrusted network data. All parsing functions validate
54//! input lengths and return errors for malformed data rather than panicking.
55//!
56//! # See Also
57//!
58//! - [`cell`](super::cell) - Cell types that use these data types for encoding
59//! - [`Relay`](super::Relay) - High-level relay connection interface
60//! - [`RelayCircuit`](super::RelayCircuit) - Circuit management using these primitives
61
62use crate::Error;
63use sha1::{Digest, Sha1};
64use std::fmt;
65use std::net::{Ipv4Addr, Ipv6Addr};
66
67/// Null byte constant used for padding in the Tor protocol.
68pub const ZERO: u8 = 0x00;
69
70/// Length of SHA-1 hash output in bytes (160 bits).
71///
72/// Used throughout the Tor protocol for identity fingerprints and
73/// key derivation functions.
74pub const HASH_LEN: usize = 20;
75
76/// Length of symmetric encryption keys in bytes (128 bits).
77///
78/// Used for AES-128-CTR encryption in relay cells.
79pub const KEY_LEN: usize = 16;
80
81/// Splits a byte slice at the given position, clamping to the slice length.
82///
83/// This is a helper function for parsing binary data that safely handles
84/// cases where the requested split position exceeds the slice length.
85///
86/// # Arguments
87///
88/// * `content` - The byte slice to split
89/// * `size` - The position at which to split (clamped to `content.len()`)
90///
91/// # Returns
92///
93/// A tuple of `(left, right)` where:
94/// - `left` contains bytes `[0..min(size, len))`
95/// - `right` contains the remaining bytes
96///
97/// # Example
98///
99/// ```rust
100/// use stem_rs::client::datatype::split;
101///
102/// let data = b"hello";
103/// let (left, right) = split(data, 2);
104/// assert_eq!(left, b"he");
105/// assert_eq!(right, b"llo");
106///
107/// // Size exceeds length - returns entire slice and empty remainder
108/// let (left, right) = split(data, 100);
109/// assert_eq!(left, b"hello");
110/// assert_eq!(right, b"");
111/// ```
112pub fn split(content: &[u8], size: usize) -> (&[u8], &[u8]) {
113 content.split_at(size.min(content.len()))
114}
115
116/// Integer size types for packing and unpacking binary data.
117///
118/// The Tor protocol uses fixed-width unsigned integers in network byte order
119/// (big-endian). This enum provides methods for encoding and decoding these
120/// integers according to the
121/// [struct pack format](https://docs.python.org/3/library/struct.html#format-characters).
122///
123/// # Variants
124///
125/// | Variant | Size | Range |
126/// |------------|---------|--------------------------|
127/// | `Char` | 1 byte | 0 to 255 |
128/// | `Short` | 2 bytes | 0 to 65,535 |
129/// | `Long` | 4 bytes | 0 to 4,294,967,295 |
130/// | `LongLong` | 8 bytes | 0 to 18,446,744,073,709,551,615 |
131///
132/// # Example
133///
134/// ```rust
135/// use stem_rs::client::datatype::Size;
136///
137/// // Pack a 16-bit port number
138/// let port: u64 = 9001;
139/// let packed = Size::Short.pack(port);
140/// assert_eq!(packed, vec![0x23, 0x29]);
141///
142/// // Unpack it back
143/// let unpacked = Size::Short.unpack(&packed).unwrap();
144/// assert_eq!(unpacked, 9001);
145///
146/// // Pop from a larger buffer
147/// let buffer = vec![0x23, 0x29, 0xFF, 0xFF];
148/// let (value, remainder) = Size::Short.pop(&buffer).unwrap();
149/// assert_eq!(value, 9001);
150/// assert_eq!(remainder, &[0xFF, 0xFF]);
151/// ```
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
153pub enum Size {
154 /// Unsigned 8-bit integer (1 byte).
155 Char,
156 /// Unsigned 16-bit integer (2 bytes, big-endian).
157 Short,
158 /// Unsigned 32-bit integer (4 bytes, big-endian).
159 Long,
160 /// Unsigned 64-bit integer (8 bytes, big-endian).
161 LongLong,
162}
163
164impl Size {
165 /// Returns the size in bytes for this integer type.
166 ///
167 /// # Example
168 ///
169 /// ```rust
170 /// use stem_rs::client::datatype::Size;
171 ///
172 /// assert_eq!(Size::Char.size(), 1);
173 /// assert_eq!(Size::Short.size(), 2);
174 /// assert_eq!(Size::Long.size(), 4);
175 /// assert_eq!(Size::LongLong.size(), 8);
176 /// ```
177 pub fn size(&self) -> usize {
178 match self {
179 Size::Char => 1,
180 Size::Short => 2,
181 Size::Long => 4,
182 Size::LongLong => 8,
183 }
184 }
185
186 /// Packs an integer value into big-endian bytes.
187 ///
188 /// # Arguments
189 ///
190 /// * `value` - The integer value to pack (truncated to fit the size)
191 ///
192 /// # Returns
193 ///
194 /// A `Vec<u8>` containing the packed bytes in network byte order.
195 ///
196 /// # Example
197 ///
198 /// ```rust
199 /// use stem_rs::client::datatype::Size;
200 ///
201 /// assert_eq!(Size::Char.pack(0x12), vec![0x12]);
202 /// assert_eq!(Size::Short.pack(0x1234), vec![0x12, 0x34]);
203 /// assert_eq!(Size::Long.pack(0x12345678), vec![0x12, 0x34, 0x56, 0x78]);
204 /// ```
205 pub fn pack(&self, value: u64) -> Vec<u8> {
206 match self {
207 Size::Char => vec![value as u8],
208 Size::Short => (value as u16).to_be_bytes().to_vec(),
209 Size::Long => (value as u32).to_be_bytes().to_vec(),
210 Size::LongLong => value.to_be_bytes().to_vec(),
211 }
212 }
213
214 /// Unpacks big-endian bytes into an integer value.
215 ///
216 /// # Arguments
217 ///
218 /// * `data` - The bytes to unpack (must be exactly `self.size()` bytes)
219 ///
220 /// # Errors
221 ///
222 /// Returns [`Error::Protocol`] if `data.len()` does not match `self.size()`.
223 ///
224 /// # Example
225 ///
226 /// ```rust
227 /// use stem_rs::client::datatype::Size;
228 ///
229 /// assert_eq!(Size::Char.unpack(&[0x12]).unwrap(), 0x12);
230 /// assert_eq!(Size::Short.unpack(&[0x12, 0x34]).unwrap(), 0x1234);
231 ///
232 /// // Wrong size returns an error
233 /// assert!(Size::Short.unpack(&[0x12]).is_err());
234 /// ```
235 pub fn unpack(&self, data: &[u8]) -> Result<u64, Error> {
236 if data.len() != self.size() {
237 return Err(Error::Protocol(format!(
238 "{:?} is the wrong size for a {:?} field",
239 data, self
240 )));
241 }
242 Ok(match self {
243 Size::Char => data[0] as u64,
244 Size::Short => u16::from_be_bytes([data[0], data[1]]) as u64,
245 Size::Long => u32::from_be_bytes([data[0], data[1], data[2], data[3]]) as u64,
246 Size::LongLong => u64::from_be_bytes([
247 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
248 ]),
249 })
250 }
251
252 /// Unpacks an integer from the start of a byte slice, returning the remainder.
253 ///
254 /// This is useful for parsing sequential fields from a binary buffer.
255 ///
256 /// # Arguments
257 ///
258 /// * `data` - The byte slice to read from (must have at least `self.size()` bytes)
259 ///
260 /// # Returns
261 ///
262 /// A tuple of `(value, remainder)` where:
263 /// - `value` is the unpacked integer
264 /// - `remainder` is the unconsumed portion of the input
265 ///
266 /// # Errors
267 ///
268 /// Returns [`Error::Protocol`] if `data.len()` is less than `self.size()`.
269 ///
270 /// # Example
271 ///
272 /// ```rust
273 /// use stem_rs::client::datatype::Size;
274 ///
275 /// let data = vec![0x00, 0x12, 0xFF, 0xFF];
276 /// let (value, rest) = Size::Short.pop(&data).unwrap();
277 /// assert_eq!(value, 18);
278 /// assert_eq!(rest, &[0xFF, 0xFF]);
279 /// ```
280 pub fn pop<'a>(&self, data: &'a [u8]) -> Result<(u64, &'a [u8]), Error> {
281 if data.len() < self.size() {
282 return Err(Error::Protocol(format!(
283 "{:?} is the wrong size for a {:?} field",
284 data, self
285 )));
286 }
287 let (to_unpack, remainder) = split(data, self.size());
288 Ok((self.unpack(to_unpack)?, remainder))
289 }
290}
291
292/// Link protocol version with version-dependent constants.
293///
294/// The Tor link protocol has evolved over time, with different versions
295/// using different field sizes and constants. This struct encapsulates
296/// the version-specific parameters needed for cell encoding and decoding.
297///
298/// # Version Differences
299///
300/// | Version | Circuit ID Size | First Circuit ID | Fixed Cell Length |
301/// |---------|-----------------|------------------|-------------------|
302/// | 1-3 | 2 bytes (Short) | 0x0001 | 512 bytes |
303/// | 4+ | 4 bytes (Long) | 0x80000000 | 514 bytes |
304///
305/// The `first_circ_id` determines the starting point for client-initiated
306/// circuit identifiers. Clients use IDs with the high bit set (version 4+)
307/// or starting from 1 (version 1-3).
308///
309/// # Example
310///
311/// ```rust
312/// use stem_rs::client::datatype::{LinkProtocol, Size};
313///
314/// // Version 3 uses 2-byte circuit IDs
315/// let v3 = LinkProtocol::new(3);
316/// assert_eq!(v3.circ_id_size, Size::Short);
317/// assert_eq!(v3.first_circ_id, 0x01);
318///
319/// // Version 5 uses 4-byte circuit IDs
320/// let v5 = LinkProtocol::new(5);
321/// assert_eq!(v5.circ_id_size, Size::Long);
322/// assert_eq!(v5.first_circ_id, 0x80000000);
323/// ```
324///
325/// # Equality
326///
327/// `LinkProtocol` can be compared directly with `u32` version numbers:
328///
329/// ```rust
330/// use stem_rs::client::datatype::LinkProtocol;
331///
332/// let protocol = LinkProtocol::new(5);
333/// assert!(protocol == 5);
334/// assert!(protocol != 4);
335/// ```
336#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
337pub struct LinkProtocol {
338 /// The link protocol version number.
339 pub version: u32,
340 /// Size of circuit identifier fields (2 or 4 bytes).
341 pub circ_id_size: Size,
342 /// Total length of fixed-size cells in bytes.
343 pub fixed_cell_length: usize,
344 /// First circuit ID to use when creating circuits.
345 ///
346 /// Clients pick circuit IDs from a range determined by the protocol version
347 /// to avoid collisions with relay-initiated circuits.
348 pub first_circ_id: u32,
349}
350
351impl LinkProtocol {
352 /// Creates a new `LinkProtocol` for the given version number.
353 ///
354 /// This automatically configures all version-dependent constants based
355 /// on the protocol specification.
356 ///
357 /// # Arguments
358 ///
359 /// * `version` - The link protocol version (typically 4 or 5 for modern Tor)
360 ///
361 /// # Example
362 ///
363 /// ```rust
364 /// use stem_rs::client::datatype::LinkProtocol;
365 ///
366 /// let protocol = LinkProtocol::new(5);
367 /// assert_eq!(protocol.version, 5);
368 /// assert_eq!(protocol.fixed_cell_length, 514);
369 /// ```
370 pub fn new(version: u32) -> Self {
371 let circ_id_size = if version > 3 { Size::Long } else { Size::Short };
372 let first_circ_id = if version > 3 { 0x80000000 } else { 0x01 };
373 let cell_header_size = circ_id_size.size() + 1;
374 let fixed_cell_length = cell_header_size + super::cell::FIXED_PAYLOAD_LEN;
375
376 LinkProtocol {
377 version,
378 circ_id_size,
379 fixed_cell_length,
380 first_circ_id,
381 }
382 }
383}
384
385impl From<u32> for LinkProtocol {
386 /// Creates a `LinkProtocol` from a version number.
387 fn from(version: u32) -> Self {
388 LinkProtocol::new(version)
389 }
390}
391
392impl PartialEq<u32> for LinkProtocol {
393 /// Compares the protocol version with a `u32`.
394 fn eq(&self, other: &u32) -> bool {
395 self.version == *other
396 }
397}
398
399/// Address type identifier for relay addresses.
400///
401/// Indicates the format of an address in the Tor protocol. This is used
402/// in NETINFO cells and other places where addresses are exchanged.
403///
404/// # Variants
405///
406/// | Variant | Value | Description |
407/// |------------------|-------|------------------------------------------|
408/// | `Hostname` | 0 | DNS hostname (not typically used) |
409/// | `IPv4` | 4 | IPv4 address (4 bytes) |
410/// | `IPv6` | 6 | IPv6 address (16 bytes) |
411/// | `ErrorTransient` | 16 | Temporary error retrieving address |
412/// | `ErrorPermanent` | 17 | Permanent error retrieving address |
413/// | `Unknown` | - | Unrecognized address type |
414///
415/// # Example
416///
417/// ```rust
418/// use stem_rs::client::datatype::AddrType;
419///
420/// let (addr_type, raw_value) = AddrType::get(4);
421/// assert_eq!(addr_type, AddrType::IPv4);
422/// assert_eq!(raw_value, 4);
423///
424/// // Unknown types preserve the raw value
425/// let (addr_type, raw_value) = AddrType::get(99);
426/// assert_eq!(addr_type, AddrType::Unknown);
427/// assert_eq!(raw_value, 99);
428/// ```
429#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
430pub enum AddrType {
431 /// DNS hostname.
432 Hostname = 0,
433 /// IPv4 address (4 bytes).
434 IPv4 = 4,
435 /// IPv6 address (16 bytes).
436 IPv6 = 6,
437 /// Temporary error retrieving the address.
438 ErrorTransient = 16,
439 /// Permanent error retrieving the address.
440 ErrorPermanent = 17,
441 /// Unrecognized address type.
442 Unknown,
443}
444
445impl AddrType {
446 /// Converts a raw byte value to an `AddrType` and its integer representation.
447 ///
448 /// # Arguments
449 ///
450 /// * `val` - The raw address type byte from the protocol
451 ///
452 /// # Returns
453 ///
454 /// A tuple of `(AddrType, u8)` where the second element is the original
455 /// byte value. This preserves unknown type values for round-tripping.
456 ///
457 /// # Example
458 ///
459 /// ```rust
460 /// use stem_rs::client::datatype::AddrType;
461 ///
462 /// assert_eq!(AddrType::get(4), (AddrType::IPv4, 4));
463 /// assert_eq!(AddrType::get(6), (AddrType::IPv6, 6));
464 /// assert_eq!(AddrType::get(99), (AddrType::Unknown, 99));
465 /// ```
466 pub fn get(val: u8) -> (AddrType, u8) {
467 match val {
468 0 => (AddrType::Hostname, 0),
469 4 => (AddrType::IPv4, 4),
470 6 => (AddrType::IPv6, 6),
471 16 => (AddrType::ErrorTransient, 16),
472 17 => (AddrType::ErrorPermanent, 17),
473 _ => (AddrType::Unknown, val),
474 }
475 }
476
477 /// Returns the integer value for this address type.
478 ///
479 /// Returns 255 for `Unknown` types (the original value is lost).
480 pub fn value(&self) -> u8 {
481 match self {
482 AddrType::Hostname => 0,
483 AddrType::IPv4 => 4,
484 AddrType::IPv6 => 6,
485 AddrType::ErrorTransient => 16,
486 AddrType::ErrorPermanent => 17,
487 AddrType::Unknown => 255,
488 }
489 }
490}
491
492/// A relay address with type information.
493///
494/// Represents an address in the Tor protocol, supporting IPv4, IPv6, and
495/// other address types. Addresses are encoded with a type byte, length byte,
496/// and variable-length value.
497///
498/// # Wire Format
499///
500/// ```text
501/// +----------+--------+------------------+
502/// | Type (1) | Len (1)| Value (Len bytes)|
503/// +----------+--------+------------------+
504/// ```
505///
506/// # Example
507///
508/// ```rust
509/// use stem_rs::client::datatype::{Address, AddrType};
510///
511/// // Create from string
512/// let addr = Address::new("127.0.0.1").unwrap();
513/// assert_eq!(addr.addr_type, AddrType::IPv4);
514/// assert_eq!(addr.value, Some("127.0.0.1".to_string()));
515///
516/// // Pack and unpack
517/// let packed = addr.pack();
518/// let unpacked = Address::unpack(&packed).unwrap();
519/// assert_eq!(addr, unpacked);
520/// ```
521///
522/// # IPv6 Handling
523///
524/// IPv6 addresses are normalized to their fully expanded form:
525///
526/// ```rust
527/// use stem_rs::client::datatype::Address;
528///
529/// let addr = Address::new("::1").unwrap();
530/// assert_eq!(addr.value, Some("0000:0000:0000:0000:0000:0000:0000:0001".to_string()));
531/// ```
532#[derive(Debug, Clone, PartialEq, Eq)]
533pub struct Address {
534 /// The type of this address.
535 pub addr_type: AddrType,
536 /// The raw type byte (preserved for unknown types).
537 pub type_int: u8,
538 /// The human-readable address string (if applicable).
539 ///
540 /// This is `None` for error types and unknown address types.
541 pub value: Option<String>,
542 /// The raw binary representation of the address.
543 pub value_bin: Vec<u8>,
544}
545
546impl Address {
547 /// Creates a new `Address` from an IP address string.
548 ///
549 /// Automatically detects whether the address is IPv4 or IPv6.
550 ///
551 /// # Arguments
552 ///
553 /// * `value` - An IPv4 or IPv6 address string
554 ///
555 /// # Errors
556 ///
557 /// Returns [`Error::Protocol`] if the string is not a valid IPv4 or IPv6 address.
558 ///
559 /// # Example
560 ///
561 /// ```rust
562 /// use stem_rs::client::datatype::{Address, AddrType};
563 ///
564 /// let ipv4 = Address::new("192.168.1.1").unwrap();
565 /// assert_eq!(ipv4.addr_type, AddrType::IPv4);
566 ///
567 /// let ipv6 = Address::new("2001:db8::1").unwrap();
568 /// assert_eq!(ipv6.addr_type, AddrType::IPv6);
569 ///
570 /// // Invalid addresses return an error
571 /// assert!(Address::new("not-an-address").is_err());
572 /// ```
573 pub fn new(value: &str) -> Result<Self, Error> {
574 if let Ok(ipv4) = value.parse::<Ipv4Addr>() {
575 return Ok(Address {
576 addr_type: AddrType::IPv4,
577 type_int: 4,
578 value: Some(value.to_string()),
579 value_bin: ipv4.octets().to_vec(),
580 });
581 }
582 if let Ok(ipv6) = value.parse::<Ipv6Addr>() {
583 let expanded = format!(
584 "{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}",
585 ipv6.segments()[0],
586 ipv6.segments()[1],
587 ipv6.segments()[2],
588 ipv6.segments()[3],
589 ipv6.segments()[4],
590 ipv6.segments()[5],
591 ipv6.segments()[6],
592 ipv6.segments()[7]
593 );
594 return Ok(Address {
595 addr_type: AddrType::IPv6,
596 type_int: 6,
597 value: Some(expanded),
598 value_bin: ipv6.octets().to_vec(),
599 });
600 }
601 Err(Error::Protocol(format!(
602 "'{}' isn't an IPv4 or IPv6 address",
603 value
604 )))
605 }
606
607 /// Creates an `Address` from raw bytes with a specified type.
608 ///
609 /// This is used when parsing addresses from the wire format where
610 /// the type is already known.
611 ///
612 /// # Arguments
613 ///
614 /// * `value` - The raw address bytes
615 /// * `addr_type` - The address type byte
616 ///
617 /// # Errors
618 ///
619 /// Returns [`Error::Protocol`] if:
620 /// - `addr_type` is 4 (IPv4) but `value` is not 4 bytes
621 /// - `addr_type` is 6 (IPv6) but `value` is not 16 bytes
622 ///
623 /// # Example
624 ///
625 /// ```rust
626 /// use stem_rs::client::datatype::{Address, AddrType};
627 ///
628 /// let addr = Address::with_type(&[127, 0, 0, 1], 4).unwrap();
629 /// assert_eq!(addr.value, Some("127.0.0.1".to_string()));
630 ///
631 /// // Unknown types are accepted
632 /// let unknown = Address::with_type(b"data", 99).unwrap();
633 /// assert_eq!(unknown.addr_type, AddrType::Unknown);
634 /// ```
635 pub fn with_type(value: &[u8], addr_type: u8) -> Result<Self, Error> {
636 let (atype, type_int) = AddrType::get(addr_type);
637 match atype {
638 AddrType::IPv4 => {
639 if value.len() != 4 {
640 return Err(Error::Protocol(format!(
641 "Packed IPv4 addresses should be four bytes, but was: {:?}",
642 value
643 )));
644 }
645 let addr_str = format!("{}.{}.{}.{}", value[0], value[1], value[2], value[3]);
646 Ok(Address {
647 addr_type: atype,
648 type_int,
649 value: Some(addr_str),
650 value_bin: value.to_vec(),
651 })
652 }
653 AddrType::IPv6 => {
654 if value.len() != 16 {
655 return Err(Error::Protocol(format!(
656 "Packed IPv6 addresses should be sixteen bytes, but was: {:?}",
657 value
658 )));
659 }
660 let addr_str = unpack_ipv6_address(value);
661 Ok(Address {
662 addr_type: atype,
663 type_int,
664 value: Some(addr_str),
665 value_bin: value.to_vec(),
666 })
667 }
668 _ => Ok(Address {
669 addr_type: atype,
670 type_int,
671 value: None,
672 value_bin: value.to_vec(),
673 }),
674 }
675 }
676
677 /// Packs the address into its wire format.
678 ///
679 /// # Returns
680 ///
681 /// A `Vec<u8>` containing: `[type, length, value...]`
682 ///
683 /// # Example
684 ///
685 /// ```rust
686 /// use stem_rs::client::datatype::Address;
687 ///
688 /// let addr = Address::new("127.0.0.1").unwrap();
689 /// let packed = addr.pack();
690 /// assert_eq!(packed, vec![0x04, 0x04, 127, 0, 0, 1]);
691 /// ```
692 pub fn pack(&self) -> Vec<u8> {
693 let mut cell = Vec::new();
694 cell.push(self.type_int);
695 cell.push(self.value_bin.len() as u8);
696 cell.extend_from_slice(&self.value_bin);
697 cell
698 }
699
700 /// Unpacks an address from its wire format.
701 ///
702 /// # Arguments
703 ///
704 /// * `data` - The packed address bytes (must be exactly the right size)
705 ///
706 /// # Errors
707 ///
708 /// Returns [`Error::Protocol`] if:
709 /// - The data is too short
710 /// - There are extra bytes after the address
711 /// - The address type/length combination is invalid
712 pub fn unpack(data: &[u8]) -> Result<Self, Error> {
713 let (addr, remainder) = Self::pop(data)?;
714 if !remainder.is_empty() {
715 return Err(Error::Protocol(format!(
716 "Address had {} extra bytes",
717 remainder.len()
718 )));
719 }
720 Ok(addr)
721 }
722
723 /// Unpacks an address from the start of a byte slice, returning the remainder.
724 ///
725 /// # Arguments
726 ///
727 /// * `content` - The byte slice to read from
728 ///
729 /// # Returns
730 ///
731 /// A tuple of `(Address, remainder)`.
732 ///
733 /// # Errors
734 ///
735 /// Returns [`Error::Protocol`] if the data is malformed.
736 pub fn pop(content: &[u8]) -> Result<(Self, &[u8]), Error> {
737 if content.len() < 2 {
738 return Err(Error::Protocol(
739 "Address requires at least 2 bytes".to_string(),
740 ));
741 }
742 let (addr_type, content) = (content[0], &content[1..]);
743 let (addr_length, content) = (content[0] as usize, &content[1..]);
744 if content.len() < addr_length {
745 return Err(Error::Protocol(format!(
746 "Address specified a payload of {} bytes, but only had {}",
747 addr_length,
748 content.len()
749 )));
750 }
751 let (addr_value, content) = split(content, addr_length);
752 Ok((Address::with_type(addr_value, addr_type)?, content))
753 }
754}
755
756/// Unpacks a 16-byte IPv6 address into its colon-separated hex string form.
757fn unpack_ipv6_address(value: &[u8]) -> String {
758 let segments: Vec<String> = (0..8)
759 .map(|i| {
760 let high = value[i * 2] as u16;
761 let low = value[i * 2 + 1] as u16;
762 format!("{:04x}", (high << 8) | low)
763 })
764 .collect();
765 segments.join(":")
766}
767
768/// Certificate type identifier.
769///
770/// Identifies the purpose of a certificate in the Tor protocol. Different
771/// certificate types are used for different authentication and signing purposes.
772///
773/// For more information, see:
774/// - [tor-spec.txt section 4.2](https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt)
775/// - [cert-spec.txt section A.1](https://gitweb.torproject.org/torspec.git/tree/cert-spec.txt)
776/// - [rend-spec-v3.txt appendix E](https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt)
777///
778/// # Variants
779///
780/// | Variant | Value | Description |
781/// |----------------------|-------|------------------------------------------------|
782/// | `Link` | 1 | Link key certificate (RSA1024 identity) |
783/// | `Identity` | 2 | RSA1024 identity certificate |
784/// | `Authenticate` | 3 | RSA1024 AUTHENTICATE cell link certificate |
785/// | `Ed25519Signing` | 4 | Ed25519 signing key (signed with identity) |
786/// | `LinkCert` | 5 | TLS link cert (signed with Ed25519 signing) |
787/// | `Ed25519Authenticate`| 6 | Ed25519 AUTHENTICATE cell key |
788/// | `Ed25519Identity` | 7 | Ed25519 identity (signed with RSA identity) |
789/// | `HsV3DescSigning` | 8 | HS v3 short-term descriptor signing key |
790/// | `HsV3IntroAuth` | 9 | HS v3 introduction point authentication key |
791/// | `NtorOnionKey` | 10 | ntor onion key cross-certifying Ed25519 |
792/// | `HsV3NtorEnc` | 11 | HS v3 ntor-extra encryption key |
793/// | `Unknown` | - | Unrecognized certificate type |
794///
795/// # Example
796///
797/// ```rust
798/// use stem_rs::client::datatype::CertType;
799///
800/// let (cert_type, raw) = CertType::get(4);
801/// assert_eq!(cert_type, CertType::Ed25519Signing);
802/// assert_eq!(format!("{}", cert_type), "ED25519_SIGNING");
803/// ```
804#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
805pub enum CertType {
806 /// Link key certificate certified by RSA1024 identity.
807 Link = 1,
808 /// RSA1024 identity certificate.
809 Identity = 2,
810 /// RSA1024 AUTHENTICATE cell link certificate.
811 Authenticate = 3,
812 /// Ed25519 signing key, signed with identity key.
813 Ed25519Signing = 4,
814 /// TLS link certificate, signed with Ed25519 signing key.
815 LinkCert = 5,
816 /// Ed25519 AUTHENTICATE cell key, signed with Ed25519 signing key.
817 Ed25519Authenticate = 6,
818 /// Ed25519 identity, signed with RSA identity.
819 Ed25519Identity = 7,
820 /// Hidden service v3 short-term descriptor signing key.
821 HsV3DescSigning = 8,
822 /// Hidden service v3 introduction point authentication key.
823 HsV3IntroAuth = 9,
824 /// ntor onion key cross-certifying Ed25519 identity key.
825 NtorOnionKey = 10,
826 /// Hidden service v3 ntor-extra encryption key.
827 HsV3NtorEnc = 11,
828 /// Unrecognized certificate type.
829 Unknown,
830}
831
832impl CertType {
833 /// Converts a raw byte value to a `CertType` and its integer representation.
834 ///
835 /// # Arguments
836 ///
837 /// * `val` - The raw certificate type byte from the protocol
838 ///
839 /// # Returns
840 ///
841 /// A tuple of `(CertType, u8)` where the second element is the original
842 /// byte value. This preserves unknown type values for round-tripping.
843 pub fn get(val: u8) -> (CertType, u8) {
844 match val {
845 1 => (CertType::Link, 1),
846 2 => (CertType::Identity, 2),
847 3 => (CertType::Authenticate, 3),
848 4 => (CertType::Ed25519Signing, 4),
849 5 => (CertType::LinkCert, 5),
850 6 => (CertType::Ed25519Authenticate, 6),
851 7 => (CertType::Ed25519Identity, 7),
852 8 => (CertType::HsV3DescSigning, 8),
853 9 => (CertType::HsV3IntroAuth, 9),
854 10 => (CertType::NtorOnionKey, 10),
855 11 => (CertType::HsV3NtorEnc, 11),
856 _ => (CertType::Unknown, val),
857 }
858 }
859
860 /// Returns the integer value for this certificate type.
861 ///
862 /// Returns 255 for `Unknown` types.
863 pub fn value(&self) -> u8 {
864 match self {
865 CertType::Link => 1,
866 CertType::Identity => 2,
867 CertType::Authenticate => 3,
868 CertType::Ed25519Signing => 4,
869 CertType::LinkCert => 5,
870 CertType::Ed25519Authenticate => 6,
871 CertType::Ed25519Identity => 7,
872 CertType::HsV3DescSigning => 8,
873 CertType::HsV3IntroAuth => 9,
874 CertType::NtorOnionKey => 10,
875 CertType::HsV3NtorEnc => 11,
876 CertType::Unknown => 255,
877 }
878 }
879}
880
881impl fmt::Display for CertType {
882 /// Formats the certificate type as its canonical string name.
883 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
884 match self {
885 CertType::Link => write!(f, "LINK"),
886 CertType::Identity => write!(f, "IDENTITY"),
887 CertType::Authenticate => write!(f, "AUTHENTICATE"),
888 CertType::Ed25519Signing => write!(f, "ED25519_SIGNING"),
889 CertType::LinkCert => write!(f, "LINK_CERT"),
890 CertType::Ed25519Authenticate => write!(f, "ED25519_AUTHENTICATE"),
891 CertType::Ed25519Identity => write!(f, "ED25519_IDENTITY"),
892 CertType::HsV3DescSigning => write!(f, "HS_V3_DESC_SIGNING"),
893 CertType::HsV3IntroAuth => write!(f, "HS_V3_INTRO_AUTH"),
894 CertType::NtorOnionKey => write!(f, "NTOR_ONION_KEY"),
895 CertType::HsV3NtorEnc => write!(f, "HS_V3_NTOR_ENC"),
896 CertType::Unknown => write!(f, "UNKNOWN"),
897 }
898 }
899}
900
901/// A relay certificate as defined in tor-spec section 4.2.
902///
903/// Certificates are used in CERTS cells to authenticate relays during
904/// the link handshake. Each certificate has a type and a variable-length
905/// value containing the actual certificate data.
906///
907/// # Wire Format
908///
909/// ```text
910/// +----------+------------+------------------+
911/// | Type (1) | Length (2) | Value (Len bytes)|
912/// +----------+------------+------------------+
913/// ```
914///
915/// Note that the length field is 2 bytes (unlike Address which uses 1 byte).
916///
917/// # Example
918///
919/// ```rust
920/// use stem_rs::client::datatype::{Certificate, CertType};
921///
922/// // Create a certificate
923/// let cert = Certificate::new(CertType::Link, vec![0x01, 0x02, 0x03]);
924/// assert_eq!(cert.cert_type, CertType::Link);
925///
926/// // Pack and unpack
927/// let packed = cert.pack();
928/// let (unpacked, _) = Certificate::pop(&packed).unwrap();
929/// assert_eq!(cert, unpacked);
930/// ```
931#[derive(Debug, Clone, PartialEq, Eq)]
932pub struct Certificate {
933 /// The type of this certificate.
934 pub cert_type: CertType,
935 /// The raw type byte (preserved for unknown types).
936 pub type_int: u8,
937 /// The certificate data.
938 pub value: Vec<u8>,
939}
940
941impl Certificate {
942 /// Creates a new certificate with the given type and value.
943 ///
944 /// # Arguments
945 ///
946 /// * `cert_type` - The certificate type
947 /// * `value` - The certificate data
948 pub fn new(cert_type: CertType, value: Vec<u8>) -> Self {
949 Certificate {
950 type_int: cert_type.value(),
951 cert_type,
952 value,
953 }
954 }
955
956 /// Creates a certificate from a raw type byte and value.
957 ///
958 /// This is used when parsing certificates from the wire format.
959 ///
960 /// # Arguments
961 ///
962 /// * `cert_type` - The raw certificate type byte
963 /// * `value` - The certificate data
964 pub fn from_int(cert_type: u8, value: Vec<u8>) -> Self {
965 let (ctype, type_int) = CertType::get(cert_type);
966 Certificate {
967 cert_type: ctype,
968 type_int,
969 value,
970 }
971 }
972
973 /// Packs the certificate into its wire format.
974 ///
975 /// # Returns
976 ///
977 /// A `Vec<u8>` containing: `[type (1), length (2), value...]`
978 pub fn pack(&self) -> Vec<u8> {
979 let mut cell = Vec::new();
980 cell.push(self.type_int);
981 cell.extend_from_slice(&Size::Short.pack(self.value.len() as u64));
982 cell.extend_from_slice(&self.value);
983 cell
984 }
985
986 /// Unpacks a certificate from the start of a byte slice, returning the remainder.
987 ///
988 /// # Arguments
989 ///
990 /// * `content` - The byte slice to read from
991 ///
992 /// # Returns
993 ///
994 /// A tuple of `(Certificate, remainder)`.
995 ///
996 /// # Errors
997 ///
998 /// Returns [`Error::Protocol`] if:
999 /// - The data is too short for the header
1000 /// - The specified length exceeds the available data
1001 pub fn pop(content: &[u8]) -> Result<(Self, &[u8]), Error> {
1002 if content.is_empty() {
1003 return Err(Error::Protocol(
1004 "Certificate requires at least 1 byte".to_string(),
1005 ));
1006 }
1007 let (cert_type, content) = (content[0], &content[1..]);
1008 let (cert_size, content) = Size::Short.pop(content)?;
1009 let cert_size = cert_size as usize;
1010 if cert_size > content.len() {
1011 return Err(Error::Protocol(format!(
1012 "CERTS cell should have a certificate with {} bytes, but only had {} remaining",
1013 cert_size,
1014 content.len()
1015 )));
1016 }
1017 let (cert_bytes, content) = split(content, cert_size);
1018 Ok((
1019 Certificate::from_int(cert_type, cert_bytes.to_vec()),
1020 content,
1021 ))
1022 }
1023}
1024
1025/// Relay cell command types.
1026///
1027/// Commands used within relay cells to manage streams and circuits.
1028/// These commands have two characteristics:
1029///
1030/// - **Direction**: Forward commands originate from the client; backward
1031/// commands come from the relay.
1032/// - **Scope**: Stream commands affect individual streams; circuit commands
1033/// affect the entire circuit.
1034///
1035/// # Variants
1036///
1037/// | Command | Value | Direction | Scope | Description |
1038/// |-------------|-------|------------------|---------|--------------------------------|
1039/// | `Begin` | 1 | Forward | Stream | Begin a new stream |
1040/// | `Data` | 2 | Forward/Backward | Stream | Transmit data |
1041/// | `End` | 3 | Forward/Backward | Stream | End a stream |
1042/// | `Connected` | 4 | Backward | Stream | Reply to BEGIN |
1043/// | `SendMe` | 5 | Forward/Backward | Both | Flow control acknowledgment |
1044/// | `Extend` | 6 | Forward | Circuit | Extend circuit (legacy) |
1045/// | `Extended` | 7 | Backward | Circuit | Reply to EXTEND |
1046/// | `Truncate` | 8 | Forward | Circuit | Remove last hop |
1047/// | `Truncated` | 9 | Backward | Circuit | Reply to TRUNCATE |
1048/// | `Drop` | 10 | Forward/Backward | Circuit | Ignorable no-op |
1049/// | `Resolve` | 11 | Forward | Stream | DNS resolution request |
1050/// | `Resolved` | 12 | Backward | Stream | Reply to RESOLVE |
1051/// | `BeginDir` | 13 | Forward | Stream | Request directory info |
1052/// | `Extend2` | 14 | Forward | Circuit | Extend circuit (ntor) |
1053/// | `Extended2` | 15 | Backward | Circuit | Reply to EXTEND2 |
1054/// | `Unknown` | - | - | - | Unrecognized command |
1055///
1056/// # Example
1057///
1058/// ```rust
1059/// use stem_rs::client::datatype::RelayCommand;
1060///
1061/// let (cmd, raw) = RelayCommand::get(1);
1062/// assert_eq!(cmd, RelayCommand::Begin);
1063/// assert_eq!(format!("{}", cmd), "RELAY_BEGIN");
1064/// ```
1065#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1066pub enum RelayCommand {
1067 /// Begin a new stream (forward, stream).
1068 Begin = 1,
1069 /// Transmit data (forward/backward, stream).
1070 Data = 2,
1071 /// End a stream (forward/backward, stream).
1072 End = 3,
1073 /// Reply to BEGIN (backward, stream).
1074 Connected = 4,
1075 /// Flow control - ready for more cells (forward/backward, stream/circuit).
1076 SendMe = 5,
1077 /// Extend circuit through another relay - legacy (forward, circuit).
1078 Extend = 6,
1079 /// Reply to EXTEND (backward, circuit).
1080 Extended = 7,
1081 /// Remove last circuit hop (forward, circuit).
1082 Truncate = 8,
1083 /// Reply to TRUNCATE (backward, circuit).
1084 Truncated = 9,
1085 /// Ignorable no-op (forward/backward, circuit).
1086 Drop = 10,
1087 /// Request DNS resolution (forward, stream).
1088 Resolve = 11,
1089 /// Reply to RESOLVE (backward, stream).
1090 Resolved = 12,
1091 /// Request directory information (forward, stream).
1092 BeginDir = 13,
1093 /// Extend circuit - ntor handshake (forward, circuit).
1094 Extend2 = 14,
1095 /// Reply to EXTEND2 (backward, circuit).
1096 Extended2 = 15,
1097 /// Unrecognized command.
1098 Unknown,
1099}
1100
1101impl RelayCommand {
1102 /// Converts a raw byte value to a `RelayCommand` and its integer representation.
1103 ///
1104 /// # Arguments
1105 ///
1106 /// * `val` - The raw command byte from the relay cell
1107 ///
1108 /// # Returns
1109 ///
1110 /// A tuple of `(RelayCommand, u8)` where the second element is the original
1111 /// byte value.
1112 pub fn get(val: u8) -> (RelayCommand, u8) {
1113 match val {
1114 1 => (RelayCommand::Begin, 1),
1115 2 => (RelayCommand::Data, 2),
1116 3 => (RelayCommand::End, 3),
1117 4 => (RelayCommand::Connected, 4),
1118 5 => (RelayCommand::SendMe, 5),
1119 6 => (RelayCommand::Extend, 6),
1120 7 => (RelayCommand::Extended, 7),
1121 8 => (RelayCommand::Truncate, 8),
1122 9 => (RelayCommand::Truncated, 9),
1123 10 => (RelayCommand::Drop, 10),
1124 11 => (RelayCommand::Resolve, 11),
1125 12 => (RelayCommand::Resolved, 12),
1126 13 => (RelayCommand::BeginDir, 13),
1127 14 => (RelayCommand::Extend2, 14),
1128 15 => (RelayCommand::Extended2, 15),
1129 _ => (RelayCommand::Unknown, val),
1130 }
1131 }
1132
1133 /// Returns the integer value for this relay command.
1134 ///
1135 /// Returns 255 for `Unknown` commands.
1136 pub fn value(&self) -> u8 {
1137 match self {
1138 RelayCommand::Begin => 1,
1139 RelayCommand::Data => 2,
1140 RelayCommand::End => 3,
1141 RelayCommand::Connected => 4,
1142 RelayCommand::SendMe => 5,
1143 RelayCommand::Extend => 6,
1144 RelayCommand::Extended => 7,
1145 RelayCommand::Truncate => 8,
1146 RelayCommand::Truncated => 9,
1147 RelayCommand::Drop => 10,
1148 RelayCommand::Resolve => 11,
1149 RelayCommand::Resolved => 12,
1150 RelayCommand::BeginDir => 13,
1151 RelayCommand::Extend2 => 14,
1152 RelayCommand::Extended2 => 15,
1153 RelayCommand::Unknown => 255,
1154 }
1155 }
1156}
1157
1158impl fmt::Display for RelayCommand {
1159 /// Formats the relay command as its canonical string name.
1160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1161 match self {
1162 RelayCommand::Begin => write!(f, "RELAY_BEGIN"),
1163 RelayCommand::Data => write!(f, "RELAY_DATA"),
1164 RelayCommand::End => write!(f, "RELAY_END"),
1165 RelayCommand::Connected => write!(f, "RELAY_CONNECTED"),
1166 RelayCommand::SendMe => write!(f, "RELAY_SENDME"),
1167 RelayCommand::Extend => write!(f, "RELAY_EXTEND"),
1168 RelayCommand::Extended => write!(f, "RELAY_EXTENDED"),
1169 RelayCommand::Truncate => write!(f, "RELAY_TRUNCATE"),
1170 RelayCommand::Truncated => write!(f, "RELAY_TRUNCATED"),
1171 RelayCommand::Drop => write!(f, "RELAY_DROP"),
1172 RelayCommand::Resolve => write!(f, "RELAY_RESOLVE"),
1173 RelayCommand::Resolved => write!(f, "RELAY_RESOLVED"),
1174 RelayCommand::BeginDir => write!(f, "RELAY_BEGIN_DIR"),
1175 RelayCommand::Extend2 => write!(f, "RELAY_EXTEND2"),
1176 RelayCommand::Extended2 => write!(f, "RELAY_EXTENDED2"),
1177 RelayCommand::Unknown => write!(f, "UNKNOWN"),
1178 }
1179 }
1180}
1181
1182/// Reason for closing a circuit or stream.
1183///
1184/// These codes indicate why a relay closed a circuit or stream. They are
1185/// used in DESTROY cells and RELAY_END cells.
1186///
1187/// # Variants
1188///
1189/// | Reason | Value | Description |
1190/// |-----------------|-------|------------------------------------------------|
1191/// | `None` | 0 | No reason given |
1192/// | `Protocol` | 1 | Tor protocol violation |
1193/// | `Internal` | 2 | Internal error |
1194/// | `Requested` | 3 | Client sent TRUNCATE command |
1195/// | `Hibernating` | 4 | Relay suspended to save bandwidth |
1196/// | `ResourceLimit` | 5 | Out of memory, sockets, or circuit IDs |
1197/// | `ConnectFailed` | 6 | Unable to reach relay |
1198/// | `OrIdentity` | 7 | Connected but OR identity was wrong |
1199/// | `ChannelClosed` | 8 | Connection carrying this circuit died |
1200/// | `Finished` | 9 | Circuit expired (dirty or old) |
1201/// | `Timeout` | 10 | Circuit construction took too long |
1202/// | `Destroyed` | 11 | Circuit destroyed without client TRUNCATE |
1203/// | `NoSuchService` | 12 | Request for unknown hidden service |
1204/// | `Unknown` | - | Unrecognized reason |
1205///
1206/// # Example
1207///
1208/// ```rust
1209/// use stem_rs::client::datatype::CloseReason;
1210///
1211/// let (reason, raw) = CloseReason::get(3);
1212/// assert_eq!(reason, CloseReason::Requested);
1213/// assert_eq!(format!("{}", reason), "REQUESTED");
1214/// ```
1215#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1216pub enum CloseReason {
1217 /// No reason given.
1218 None = 0,
1219 /// Tor protocol violation.
1220 Protocol = 1,
1221 /// Internal error.
1222 Internal = 2,
1223 /// Client sent a TRUNCATE command.
1224 Requested = 3,
1225 /// Relay suspended, trying to save bandwidth.
1226 Hibernating = 4,
1227 /// Out of memory, sockets, or circuit IDs.
1228 ResourceLimit = 5,
1229 /// Unable to reach relay.
1230 ConnectFailed = 6,
1231 /// Connected, but its OR identity was not as expected.
1232 OrIdentity = 7,
1233 /// Connection that was carrying this circuit died.
1234 ChannelClosed = 8,
1235 /// Circuit has expired for being dirty or old.
1236 Finished = 9,
1237 /// Circuit construction took too long.
1238 Timeout = 10,
1239 /// Circuit was destroyed without a client TRUNCATE.
1240 Destroyed = 11,
1241 /// Request was for an unknown hidden service.
1242 NoSuchService = 12,
1243 /// Unrecognized reason.
1244 Unknown,
1245}
1246
1247impl CloseReason {
1248 /// Converts a raw byte value to a `CloseReason` and its integer representation.
1249 ///
1250 /// # Arguments
1251 ///
1252 /// * `val` - The raw reason byte from the protocol
1253 ///
1254 /// # Returns
1255 ///
1256 /// A tuple of `(CloseReason, u8)` where the second element is the original
1257 /// byte value.
1258 pub fn get(val: u8) -> (CloseReason, u8) {
1259 match val {
1260 0 => (CloseReason::None, 0),
1261 1 => (CloseReason::Protocol, 1),
1262 2 => (CloseReason::Internal, 2),
1263 3 => (CloseReason::Requested, 3),
1264 4 => (CloseReason::Hibernating, 4),
1265 5 => (CloseReason::ResourceLimit, 5),
1266 6 => (CloseReason::ConnectFailed, 6),
1267 7 => (CloseReason::OrIdentity, 7),
1268 8 => (CloseReason::ChannelClosed, 8),
1269 9 => (CloseReason::Finished, 9),
1270 10 => (CloseReason::Timeout, 10),
1271 11 => (CloseReason::Destroyed, 11),
1272 12 => (CloseReason::NoSuchService, 12),
1273 _ => (CloseReason::Unknown, val),
1274 }
1275 }
1276
1277 /// Returns the integer value for this close reason.
1278 ///
1279 /// Returns 255 for `Unknown` reasons.
1280 pub fn value(&self) -> u8 {
1281 match self {
1282 CloseReason::None => 0,
1283 CloseReason::Protocol => 1,
1284 CloseReason::Internal => 2,
1285 CloseReason::Requested => 3,
1286 CloseReason::Hibernating => 4,
1287 CloseReason::ResourceLimit => 5,
1288 CloseReason::ConnectFailed => 6,
1289 CloseReason::OrIdentity => 7,
1290 CloseReason::ChannelClosed => 8,
1291 CloseReason::Finished => 9,
1292 CloseReason::Timeout => 10,
1293 CloseReason::Destroyed => 11,
1294 CloseReason::NoSuchService => 12,
1295 CloseReason::Unknown => 255,
1296 }
1297 }
1298}
1299
1300impl fmt::Display for CloseReason {
1301 /// Formats the close reason as its canonical string name.
1302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1303 match self {
1304 CloseReason::None => write!(f, "NONE"),
1305 CloseReason::Protocol => write!(f, "PROTOCOL"),
1306 CloseReason::Internal => write!(f, "INTERNAL"),
1307 CloseReason::Requested => write!(f, "REQUESTED"),
1308 CloseReason::Hibernating => write!(f, "HIBERNATING"),
1309 CloseReason::ResourceLimit => write!(f, "RESOURCELIMIT"),
1310 CloseReason::ConnectFailed => write!(f, "CONNECTFAILED"),
1311 CloseReason::OrIdentity => write!(f, "OR_IDENTITY"),
1312 CloseReason::ChannelClosed => write!(f, "CHANNEL_CLOSED"),
1313 CloseReason::Finished => write!(f, "FINISHED"),
1314 CloseReason::Timeout => write!(f, "TIMEOUT"),
1315 CloseReason::Destroyed => write!(f, "DESTROYED"),
1316 CloseReason::NoSuchService => write!(f, "NOSUCHSERVICE"),
1317 CloseReason::Unknown => write!(f, "UNKNOWN"),
1318 }
1319 }
1320}
1321
1322/// Method of communicating with a relay in a circuit.
1323///
1324/// Link specifiers describe how to connect to a relay when extending a circuit.
1325/// They are used in EXTEND2 cells to specify the next hop. Multiple specifiers
1326/// can be provided to give the extending relay options for how to connect.
1327///
1328/// For more information, see the
1329/// [EXTEND cell specification](https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt#n975).
1330///
1331/// # Wire Format
1332///
1333/// ```text
1334/// +----------+--------+------------------+
1335/// | Type (1) | Len (1)| Value (Len bytes)|
1336/// +----------+--------+------------------+
1337/// ```
1338///
1339/// # Variants
1340///
1341/// | Type | Value Size | Description |
1342/// |------|------------|--------------------------------------|
1343/// | 0 | 6 bytes | IPv4 address (4) + port (2) |
1344/// | 1 | 18 bytes | IPv6 address (16) + port (2) |
1345/// | 2 | 20 bytes | SHA-1 identity fingerprint |
1346/// | 3 | 32 bytes | Ed25519 identity fingerprint |
1347/// | 4+ | variable | Unknown/future types |
1348///
1349/// # Example
1350///
1351/// ```rust
1352/// use stem_rs::client::datatype::LinkSpecifier;
1353///
1354/// // Create an IPv4 link specifier
1355/// let spec = LinkSpecifier::IPv4 {
1356/// address: "192.168.1.1".to_string(),
1357/// port: 9001,
1358/// };
1359///
1360/// // Pack and unpack
1361/// let packed = spec.pack();
1362/// let (unpacked, _) = LinkSpecifier::pop(&packed).unwrap();
1363///
1364/// match unpacked {
1365/// LinkSpecifier::IPv4 { address, port } => {
1366/// assert_eq!(address, "192.168.1.1");
1367/// assert_eq!(port, 9001);
1368/// }
1369/// _ => panic!("Expected IPv4"),
1370/// }
1371/// ```
1372#[derive(Debug, Clone, PartialEq, Eq)]
1373pub enum LinkSpecifier {
1374 /// TLS connection to an IPv4 address.
1375 IPv4 {
1376 /// The relay's IPv4 address.
1377 address: String,
1378 /// The relay's ORPort.
1379 port: u16,
1380 },
1381 /// TLS connection to an IPv6 address.
1382 IPv6 {
1383 /// The relay's IPv6 address (fully expanded form).
1384 address: String,
1385 /// The relay's ORPort.
1386 port: u16,
1387 },
1388 /// SHA-1 identity fingerprint (20 bytes).
1389 Fingerprint {
1390 /// The relay's SHA-1 identity fingerprint.
1391 fingerprint: [u8; 20],
1392 },
1393 /// Ed25519 identity fingerprint (32 bytes).
1394 Ed25519 {
1395 /// The relay's Ed25519 identity fingerprint.
1396 fingerprint: [u8; 32],
1397 },
1398 /// Unrecognized link specifier type.
1399 Unknown {
1400 /// The raw link type byte.
1401 link_type: u8,
1402 /// The raw value bytes.
1403 value: Vec<u8>,
1404 },
1405}
1406
1407impl LinkSpecifier {
1408 /// Returns the link type byte for this specifier.
1409 ///
1410 /// | Type | Meaning |
1411 /// |------|-------------|
1412 /// | 0 | IPv4 |
1413 /// | 1 | IPv6 |
1414 /// | 2 | Fingerprint |
1415 /// | 3 | Ed25519 |
1416 /// | 4+ | Unknown |
1417 pub fn link_type(&self) -> u8 {
1418 match self {
1419 LinkSpecifier::IPv4 { .. } => 0,
1420 LinkSpecifier::IPv6 { .. } => 1,
1421 LinkSpecifier::Fingerprint { .. } => 2,
1422 LinkSpecifier::Ed25519 { .. } => 3,
1423 LinkSpecifier::Unknown { link_type, .. } => *link_type,
1424 }
1425 }
1426
1427 /// Returns the encoded value bytes for this specifier.
1428 ///
1429 /// The format depends on the specifier type:
1430 /// - IPv4: 4-byte address + 2-byte port
1431 /// - IPv6: 16-byte address + 2-byte port
1432 /// - Fingerprint: 20-byte SHA-1 hash
1433 /// - Ed25519: 32-byte public key
1434 pub fn value(&self) -> Vec<u8> {
1435 match self {
1436 LinkSpecifier::IPv4 { address, port } => {
1437 let mut value = pack_ipv4_address(address);
1438 value.extend_from_slice(&port.to_be_bytes());
1439 value
1440 }
1441 LinkSpecifier::IPv6 { address, port } => {
1442 let mut value = pack_ipv6_address(address);
1443 value.extend_from_slice(&port.to_be_bytes());
1444 value
1445 }
1446 LinkSpecifier::Fingerprint { fingerprint } => fingerprint.to_vec(),
1447 LinkSpecifier::Ed25519 { fingerprint } => fingerprint.to_vec(),
1448 LinkSpecifier::Unknown { value, .. } => value.clone(),
1449 }
1450 }
1451
1452 /// Packs the link specifier into its wire format.
1453 ///
1454 /// # Returns
1455 ///
1456 /// A `Vec<u8>` containing: `[type (1), length (1), value...]`
1457 pub fn pack(&self) -> Vec<u8> {
1458 let value = self.value();
1459 let mut cell = Vec::new();
1460 cell.push(self.link_type());
1461 cell.push(value.len() as u8);
1462 cell.extend_from_slice(&value);
1463 cell
1464 }
1465
1466 /// Unpacks a link specifier from its wire format.
1467 ///
1468 /// # Arguments
1469 ///
1470 /// * `data` - The packed link specifier bytes
1471 ///
1472 /// # Errors
1473 ///
1474 /// Returns [`Error::Protocol`] if the data is malformed.
1475 pub fn unpack(data: &[u8]) -> Result<Self, Error> {
1476 let (spec, _) = Self::pop(data)?;
1477 Ok(spec)
1478 }
1479
1480 /// Unpacks a link specifier from the start of a byte slice, returning the remainder.
1481 ///
1482 /// # Arguments
1483 ///
1484 /// * `packed` - The byte slice to read from
1485 ///
1486 /// # Returns
1487 ///
1488 /// A tuple of `(LinkSpecifier, remainder)`.
1489 ///
1490 /// # Errors
1491 ///
1492 /// Returns [`Error::Protocol`] if:
1493 /// - The data is too short for the header
1494 /// - The specified length exceeds the available data
1495 /// - The value size doesn't match the expected size for the type
1496 pub fn pop(packed: &[u8]) -> Result<(Self, &[u8]), Error> {
1497 if packed.len() < 2 {
1498 return Err(Error::Protocol(
1499 "Link specifier requires at least 2 bytes".to_string(),
1500 ));
1501 }
1502 let (link_type, packed) = (packed[0], &packed[1..]);
1503 let (value_size, packed) = (packed[0] as usize, &packed[1..]);
1504 if value_size > packed.len() {
1505 return Err(Error::Protocol(format!(
1506 "Link specifier should have {} bytes, but only had {} remaining",
1507 value_size,
1508 packed.len()
1509 )));
1510 }
1511 let (value, packed) = split(packed, value_size);
1512
1513 let specifier = match link_type {
1514 0 => {
1515 if value.len() != 6 {
1516 return Err(Error::Protocol(format!(
1517 "IPv4 link specifiers should be six bytes, but was {} instead",
1518 value.len()
1519 )));
1520 }
1521 let (addr, port_bytes) = split(value, 4);
1522 let address = format!("{}.{}.{}.{}", addr[0], addr[1], addr[2], addr[3]);
1523 let port = u16::from_be_bytes([port_bytes[0], port_bytes[1]]);
1524 LinkSpecifier::IPv4 { address, port }
1525 }
1526 1 => {
1527 if value.len() != 18 {
1528 return Err(Error::Protocol(format!(
1529 "IPv6 link specifiers should be eighteen bytes, but was {} instead",
1530 value.len()
1531 )));
1532 }
1533 let (addr, port_bytes) = split(value, 16);
1534 let address = unpack_ipv6_address(addr);
1535 let port = u16::from_be_bytes([port_bytes[0], port_bytes[1]]);
1536 LinkSpecifier::IPv6 { address, port }
1537 }
1538 2 => {
1539 if value.len() != 20 {
1540 return Err(Error::Protocol(format!(
1541 "Fingerprint link specifiers should be twenty bytes, but was {} instead",
1542 value.len()
1543 )));
1544 }
1545 let mut fingerprint = [0u8; 20];
1546 fingerprint.copy_from_slice(value);
1547 LinkSpecifier::Fingerprint { fingerprint }
1548 }
1549 3 => {
1550 if value.len() != 32 {
1551 return Err(Error::Protocol(format!(
1552 "Ed25519 link specifiers should be thirty two bytes, but was {} instead",
1553 value.len()
1554 )));
1555 }
1556 let mut fingerprint = [0u8; 32];
1557 fingerprint.copy_from_slice(value);
1558 LinkSpecifier::Ed25519 { fingerprint }
1559 }
1560 _ => LinkSpecifier::Unknown {
1561 link_type,
1562 value: value.to_vec(),
1563 },
1564 };
1565
1566 Ok((specifier, packed))
1567 }
1568}
1569
1570/// Packs an IPv4 address string into 4 bytes.
1571fn pack_ipv4_address(address: &str) -> Vec<u8> {
1572 address
1573 .split('.')
1574 .filter_map(|s| s.parse::<u8>().ok())
1575 .collect()
1576}
1577
1578/// Packs an IPv6 address string into 16 bytes.
1579fn pack_ipv6_address(address: &str) -> Vec<u8> {
1580 let mut result = Vec::with_capacity(16);
1581 for segment in address.split(':') {
1582 if let Ok(val) = u16::from_str_radix(segment, 16) {
1583 result.extend_from_slice(&val.to_be_bytes());
1584 }
1585 }
1586 result
1587}
1588
1589/// KDF-TOR derived key material.
1590///
1591/// Contains the cryptographic keys and digests derived from shared key material
1592/// during circuit creation. This implements the KDF-TOR key derivation function
1593/// as defined in tor-spec section 5.2.1.
1594///
1595/// The derivation uses SHA-1 in a counter mode:
1596/// ```text
1597/// K = H(K0 | [00]) | H(K0 | [01]) | H(K0 | [02]) | ...
1598/// ```
1599///
1600/// Where `K0` is the input key material and `H` is SHA-1.
1601///
1602/// # Fields
1603///
1604/// The derived key material is split into five parts:
1605///
1606/// | Field | Size | Purpose |
1607/// |------------------|----------|--------------------------------------|
1608/// | `key_hash` | 20 bytes | Proves knowledge of shared key |
1609/// | `forward_digest` | 20 bytes | Forward digest hash seed |
1610/// | `backward_digest`| 20 bytes | Backward digest hash seed |
1611/// | `forward_key` | 16 bytes | Forward encryption key (AES-128) |
1612/// | `backward_key` | 16 bytes | Backward encryption key (AES-128) |
1613///
1614/// # Example
1615///
1616/// ```rust
1617/// use stem_rs::client::datatype::KDF;
1618///
1619/// // Derive keys from shared secret (e.g., from CREATE_FAST handshake)
1620/// let key_material = b"shared_secret_from_handshake____";
1621/// let kdf = KDF::from_value(key_material);
1622///
1623/// // Use the derived keys for encryption
1624/// assert_eq!(kdf.forward_key.len(), 16);
1625/// assert_eq!(kdf.backward_key.len(), 16);
1626/// ```
1627///
1628/// # Security
1629///
1630/// This KDF is used with the TAP and CREATE_FAST handshakes. Modern Tor
1631/// circuits use the ntor handshake with a different KDF (HKDF-SHA256).
1632#[derive(Debug, Clone, PartialEq, Eq)]
1633pub struct KDF {
1634 /// Hash that proves knowledge of the shared key.
1635 ///
1636 /// This is compared with the value sent by the relay to verify
1637 /// both parties derived the same key material.
1638 pub key_hash: [u8; HASH_LEN],
1639 /// Forward digest hash seed.
1640 ///
1641 /// Used to initialize the running digest for cells sent from
1642 /// client to relay.
1643 pub forward_digest: [u8; HASH_LEN],
1644 /// Backward digest hash seed.
1645 ///
1646 /// Used to initialize the running digest for cells sent from
1647 /// relay to client.
1648 pub backward_digest: [u8; HASH_LEN],
1649 /// Forward encryption key (AES-128-CTR).
1650 ///
1651 /// Used to encrypt relay cells sent from client to relay.
1652 pub forward_key: [u8; KEY_LEN],
1653 /// Backward encryption key (AES-128-CTR).
1654 ///
1655 /// Used to decrypt relay cells received from relay.
1656 pub backward_key: [u8; KEY_LEN],
1657}
1658
1659impl KDF {
1660 /// Derives key material from a shared secret.
1661 ///
1662 /// Implements the KDF-TOR key derivation function from tor-spec section 5.2.1.
1663 /// The input key material is expanded using SHA-1 in counter mode to produce
1664 /// the required key material.
1665 ///
1666 /// # Arguments
1667 ///
1668 /// * `key_material` - The shared secret from the circuit handshake
1669 ///
1670 /// # Returns
1671 ///
1672 /// A `KDF` struct containing all derived keys and digests.
1673 ///
1674 /// # Algorithm
1675 ///
1676 /// ```text
1677 /// derived = H(key_material | 0x00) | H(key_material | 0x01) | ...
1678 /// key_hash = derived[0..20]
1679 /// forward_digest = derived[20..40]
1680 /// backward_digest= derived[40..60]
1681 /// forward_key = derived[60..76]
1682 /// backward_key = derived[76..92]
1683 /// ```
1684 ///
1685 /// # Example
1686 ///
1687 /// ```rust
1688 /// use stem_rs::client::datatype::KDF;
1689 ///
1690 /// let shared_secret = b"example_shared_secret___________";
1691 /// let kdf = KDF::from_value(shared_secret);
1692 ///
1693 /// // All fields are populated
1694 /// assert_eq!(kdf.key_hash.len(), 20);
1695 /// assert_eq!(kdf.forward_key.len(), 16);
1696 /// ```
1697 pub fn from_value(key_material: &[u8]) -> Self {
1698 let mut derived_key = Vec::new();
1699 let mut counter: u8 = 0;
1700
1701 while derived_key.len() < KEY_LEN * 2 + HASH_LEN * 3 {
1702 let mut hasher = Sha1::new();
1703 hasher.update(key_material);
1704 hasher.update([counter]);
1705 derived_key.extend_from_slice(&hasher.finalize());
1706 counter += 1;
1707 }
1708
1709 let (key_hash, rest) = split(&derived_key, HASH_LEN);
1710 let (forward_digest, rest) = split(rest, HASH_LEN);
1711 let (backward_digest, rest) = split(rest, HASH_LEN);
1712 let (forward_key, rest) = split(rest, KEY_LEN);
1713 let (backward_key, _) = split(rest, KEY_LEN);
1714
1715 let mut kdf = KDF {
1716 key_hash: [0u8; HASH_LEN],
1717 forward_digest: [0u8; HASH_LEN],
1718 backward_digest: [0u8; HASH_LEN],
1719 forward_key: [0u8; KEY_LEN],
1720 backward_key: [0u8; KEY_LEN],
1721 };
1722
1723 kdf.key_hash.copy_from_slice(key_hash);
1724 kdf.forward_digest.copy_from_slice(forward_digest);
1725 kdf.backward_digest.copy_from_slice(backward_digest);
1726 kdf.forward_key.copy_from_slice(forward_key);
1727 kdf.backward_key.copy_from_slice(backward_key);
1728
1729 kdf
1730 }
1731}
1732
1733#[cfg(test)]
1734mod tests {
1735 use super::*;
1736
1737 #[test]
1738 fn test_size_attributes() {
1739 assert_eq!(1, Size::Char.size());
1740 assert_eq!(2, Size::Short.size());
1741 assert_eq!(4, Size::Long.size());
1742 assert_eq!(8, Size::LongLong.size());
1743 }
1744
1745 #[test]
1746 fn test_size_pack() {
1747 assert_eq!(vec![0x12], Size::Char.pack(18));
1748 assert_eq!(vec![0x00, 0x12], Size::Short.pack(18));
1749 assert_eq!(vec![0x00, 0x00, 0x00, 0x12], Size::Long.pack(18));
1750 assert_eq!(
1751 vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12],
1752 Size::LongLong.pack(18)
1753 );
1754 }
1755
1756 #[test]
1757 fn test_size_unpack() {
1758 assert_eq!(18, Size::Char.unpack(&[0x12]).unwrap());
1759 assert_eq!(18, Size::Short.unpack(&[0x00, 0x12]).unwrap());
1760 assert_eq!(18, Size::Long.unpack(&[0x00, 0x00, 0x00, 0x12]).unwrap());
1761 assert_eq!(
1762 18,
1763 Size::LongLong
1764 .unpack(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12])
1765 .unwrap()
1766 );
1767 assert_eq!(97, Size::Char.unpack(b"a").unwrap());
1768 assert_eq!(24930, Size::Short.unpack(b"ab").unwrap());
1769 assert!(Size::Char.unpack(&[0x00, 0x12]).is_err());
1770 }
1771
1772 #[test]
1773 fn test_size_pop() {
1774 assert_eq!((18, &[][..]), Size::Char.pop(&[0x12]).unwrap());
1775 assert_eq!((0, &[0x12][..]), Size::Char.pop(&[0x00, 0x12]).unwrap());
1776 assert_eq!((18, &[][..]), Size::Short.pop(&[0x00, 0x12]).unwrap());
1777 assert!(Size::Char.pop(&[]).is_err());
1778 assert!(Size::Short.pop(&[0x12]).is_err());
1779 }
1780
1781 #[test]
1782 fn test_link_protocol_attributes() {
1783 let protocol = LinkProtocol::new(1);
1784 assert_eq!(1, protocol.version);
1785 assert_eq!(Size::Short, protocol.circ_id_size);
1786 assert_eq!(512, protocol.fixed_cell_length);
1787 assert_eq!(0x01, protocol.first_circ_id);
1788
1789 let protocol = LinkProtocol::new(10);
1790 assert_eq!(10, protocol.version);
1791 assert_eq!(Size::Long, protocol.circ_id_size);
1792 assert_eq!(514, protocol.fixed_cell_length);
1793 assert_eq!(0x80000000, protocol.first_circ_id);
1794 }
1795
1796 #[test]
1797 fn test_link_protocol_equality() {
1798 let protocol = LinkProtocol::new(1);
1799 assert_eq!(LinkProtocol::new(1), protocol);
1800 assert_ne!(LinkProtocol::new(2), protocol);
1801 assert!(protocol == 1);
1802 assert!(protocol != 2);
1803 }
1804
1805 #[test]
1806 fn test_address_ipv4() {
1807 let addr = Address::new("127.0.0.1").unwrap();
1808 assert_eq!(AddrType::IPv4, addr.addr_type);
1809 assert_eq!(4, addr.type_int);
1810 assert_eq!(Some("127.0.0.1".to_string()), addr.value);
1811 assert_eq!(vec![127, 0, 0, 1], addr.value_bin);
1812 }
1813
1814 #[test]
1815 fn test_address_ipv6() {
1816 let addr = Address::new("2001:0db8:0000:0000:0000:ff00:0042:8329").unwrap();
1817 assert_eq!(AddrType::IPv6, addr.addr_type);
1818 assert_eq!(6, addr.type_int);
1819 assert_eq!(
1820 Some("2001:0db8:0000:0000:0000:ff00:0042:8329".to_string()),
1821 addr.value
1822 );
1823 }
1824
1825 #[test]
1826 fn test_address_invalid() {
1827 assert!(Address::new("nope").is_err());
1828 }
1829
1830 #[test]
1831 fn test_address_packing() {
1832 let addr = Address::new("127.0.0.1").unwrap();
1833 let packed = addr.pack();
1834 assert_eq!(vec![0x04, 0x04, 0x7f, 0x00, 0x00, 0x01], packed);
1835
1836 let unpacked = Address::unpack(&packed).unwrap();
1837 assert_eq!(addr, unpacked);
1838 }
1839
1840 #[test]
1841 fn test_address_pop() {
1842 let data = b"\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02\x00\x00\x00\x00";
1843 let (addr, content) = Address::pop(data).unwrap();
1844 assert_eq!(b"\x01\x04\x04aq\x0f\x02\x00\x00\x00\x00", content);
1845 assert_eq!(AddrType::IPv4, addr.addr_type);
1846 assert_eq!(4, addr.type_int);
1847 assert_eq!(Some("127.0.0.1".to_string()), addr.value);
1848 assert_eq!(vec![0x7f, 0x00, 0x00, 0x01], addr.value_bin);
1849 }
1850
1851 #[test]
1852 fn test_certificate_pack_pop() {
1853 let cert = Certificate::from_int(1, vec![0x08]);
1854 let packed = cert.pack();
1855 assert_eq!(vec![0x01, 0x00, 0x01, 0x08], packed);
1856
1857 let (unpacked, remainder) = Certificate::pop(&packed).unwrap();
1858 assert_eq!(cert, unpacked);
1859 assert!(remainder.is_empty());
1860 }
1861
1862 #[test]
1863 fn test_kdf_from_value() {
1864 let key_material = b"\xec\xec.\xeb7R\xf2\n\xcb\xce\x97\xf4\x86\x82\x19#\x10\x0f\x08\xf0\xa2Z\xdeJ\x8f2\x8cc\xf6\xfa\x0e\t\x83f\xc5\xe2\xb3\x94\xa8\x13";
1865 let kdf = KDF::from_value(key_material);
1866
1867 assert_eq!(
1868 b"\xca+\x81\x05\x14\x9d)o\xa6\x82\xe9B\xa8?\xf2\xaf\x85\x1b]6",
1869 &kdf.key_hash
1870 );
1871 assert_eq!(
1872 b"\xac\xcc\xbc\x91\xb1\xaf\xd7\xe0\xe9\x9dF#\xd8\xdbz\xe8\xe6\xca\x83,",
1873 &kdf.forward_digest
1874 );
1875 assert_eq!(
1876 b"*\xe5scX\xbb+\xca \xcb\xa4\xbc\xad\x0f\x95\x0cO\xcc\xac\xf1",
1877 &kdf.backward_digest
1878 );
1879 assert_eq!(
1880 b"\xc3\xbe\xc9\xe1\xf4\x90f\xdai\xf3\xf3\xf5\x14\xb5\xb9\x03",
1881 &kdf.forward_key
1882 );
1883 assert_eq!(
1884 b"U\xaf\x1e\x1b\xb1q||\x86A<_\xf7\xa0%\x86",
1885 &kdf.backward_key
1886 );
1887 }
1888
1889 #[test]
1890 fn test_link_specifier_ipv4() {
1891 let data = b"\x00\x06\x01\x02\x03\x04#)";
1892 let (spec, _) = LinkSpecifier::pop(data).unwrap();
1893
1894 match spec {
1895 LinkSpecifier::IPv4 { address, port } => {
1896 assert_eq!("1.2.3.4", address);
1897 assert_eq!(9001, port);
1898 }
1899 _ => panic!("Expected IPv4 link specifier"),
1900 }
1901
1902 let spec = LinkSpecifier::IPv4 {
1903 address: "1.2.3.4".to_string(),
1904 port: 9001,
1905 };
1906 assert_eq!(data.to_vec(), spec.pack());
1907 }
1908
1909 #[test]
1910 fn test_link_specifier_ipv6() {
1911 let data = b"\x01\x12&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01#)";
1912 let (spec, _) = LinkSpecifier::pop(data).unwrap();
1913
1914 match spec {
1915 LinkSpecifier::IPv6 { address, port } => {
1916 assert_eq!("2600:0000:0000:0000:0000:0000:0000:0001", address);
1917 assert_eq!(9001, port);
1918 }
1919 _ => panic!("Expected IPv6 link specifier"),
1920 }
1921 }
1922
1923 #[test]
1924 fn test_link_specifier_fingerprint() {
1925 let data = b"\x02\x14CCCCCCCCCCCCCCCCCCCC";
1926 let (spec, _) = LinkSpecifier::pop(data).unwrap();
1927
1928 match spec {
1929 LinkSpecifier::Fingerprint { fingerprint } => {
1930 assert_eq!(b"CCCCCCCCCCCCCCCCCCCC", &fingerprint);
1931 }
1932 _ => panic!("Expected Fingerprint link specifier"),
1933 }
1934 }
1935
1936 #[test]
1937 fn test_link_specifier_ed25519() {
1938 let data = b"\x03\x20CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC";
1939 let (spec, _) = LinkSpecifier::pop(data).unwrap();
1940
1941 match spec {
1942 LinkSpecifier::Ed25519 { fingerprint } => {
1943 assert_eq!(b"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", &fingerprint);
1944 }
1945 _ => panic!("Expected Ed25519 link specifier"),
1946 }
1947 }
1948
1949 #[test]
1950 fn test_link_specifier_unknown() {
1951 let data = b"\x04\x20CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC";
1952 let (spec, _) = LinkSpecifier::pop(data).unwrap();
1953
1954 match spec {
1955 LinkSpecifier::Unknown { link_type, value } => {
1956 assert_eq!(4, link_type);
1957 assert_eq!(b"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC".to_vec(), value);
1958 }
1959 _ => panic!("Expected Unknown link specifier"),
1960 }
1961 }
1962
1963 #[test]
1964 fn test_link_specifier_wrong_size() {
1965 let data = b"\x04\x20CCCCCCC";
1966 assert!(LinkSpecifier::pop(data).is_err());
1967 }
1968
1969 #[test]
1970 fn test_link_specifier_pack_roundtrip() {
1971 let test_inputs = [
1972 b"\x03\x20CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC".to_vec(),
1973 b"\x04\x20CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC".to_vec(),
1974 b"\x01\x12&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01#)".to_vec(),
1975 b"\x00\x06\x01\x02\x03\x04#)".to_vec(),
1976 ];
1977
1978 for val in test_inputs {
1979 let (spec, _) = LinkSpecifier::pop(&val).unwrap();
1980 assert_eq!(val, spec.pack());
1981 }
1982 }
1983
1984 #[test]
1985 fn test_address_unknown_type() {
1986 let addr = Address::with_type(b"hello", 12).unwrap();
1987 assert_eq!(AddrType::Unknown, addr.addr_type);
1988 assert_eq!(12, addr.type_int);
1989 assert_eq!(None, addr.value);
1990 assert_eq!(b"hello".to_vec(), addr.value_bin);
1991 }
1992
1993 #[test]
1994 fn test_address_ipv6_collapsed() {
1995 let addr = Address::new("2001:0DB8:AC10:FE01::").unwrap();
1996 assert_eq!(AddrType::IPv6, addr.addr_type);
1997 assert_eq!(6, addr.type_int);
1998 assert_eq!(
1999 Some("2001:0db8:ac10:fe01:0000:0000:0000:0000".to_string()),
2000 addr.value
2001 );
2002 }
2003
2004 #[test]
2005 fn test_address_ipv4_wrong_size() {
2006 let result = Address::with_type(&[0x7f, 0x00], 4);
2007 assert!(result.is_err());
2008 }
2009
2010 #[test]
2011 fn test_address_ipv6_wrong_size() {
2012 let result = Address::with_type(&[0x7f, 0x00], 6);
2013 assert!(result.is_err());
2014 }
2015
2016 #[test]
2017 fn test_certificate_unknown_type() {
2018 let cert = Certificate::from_int(12, b"hello".to_vec());
2019 assert_eq!(CertType::Unknown, cert.cert_type);
2020 assert_eq!(12, cert.type_int);
2021 assert_eq!(b"hello".to_vec(), cert.value);
2022 }
2023
2024 #[test]
2025 fn test_certificate_all_types() {
2026 let test_data = [
2027 (1, CertType::Link),
2028 (2, CertType::Identity),
2029 (3, CertType::Authenticate),
2030 (4, CertType::Ed25519Signing),
2031 (5, CertType::LinkCert),
2032 (6, CertType::Ed25519Authenticate),
2033 (7, CertType::Ed25519Identity),
2034 ];
2035
2036 for (type_int, expected_type) in test_data {
2037 let cert = Certificate::from_int(type_int, vec![0x7f, 0x00, 0x00, 0x01]);
2038 assert_eq!(expected_type, cert.cert_type);
2039 assert_eq!(type_int, cert.type_int);
2040 assert_eq!(vec![0x7f, 0x00, 0x00, 0x01], cert.value);
2041 }
2042 }
2043
2044 #[test]
2045 fn test_addr_type_get() {
2046 assert_eq!((AddrType::IPv4, 4), AddrType::get(4));
2047 assert_eq!((AddrType::IPv6, 6), AddrType::get(6));
2048 assert_eq!((AddrType::Hostname, 0), AddrType::get(0));
2049 assert_eq!((AddrType::ErrorTransient, 16), AddrType::get(16));
2050 assert_eq!((AddrType::ErrorPermanent, 17), AddrType::get(17));
2051 assert_eq!((AddrType::Unknown, 25), AddrType::get(25));
2052 }
2053
2054 #[test]
2055 fn test_relay_command_get() {
2056 assert_eq!((RelayCommand::Begin, 1), RelayCommand::get(1));
2057 assert_eq!((RelayCommand::Data, 2), RelayCommand::get(2));
2058 assert_eq!((RelayCommand::End, 3), RelayCommand::get(3));
2059 assert_eq!((RelayCommand::BeginDir, 13), RelayCommand::get(13));
2060 assert_eq!((RelayCommand::Unknown, 99), RelayCommand::get(99));
2061 }
2062
2063 #[test]
2064 fn test_close_reason_get() {
2065 assert_eq!((CloseReason::None, 0), CloseReason::get(0));
2066 assert_eq!((CloseReason::Protocol, 1), CloseReason::get(1));
2067 assert_eq!((CloseReason::Requested, 3), CloseReason::get(3));
2068 assert_eq!((CloseReason::Finished, 9), CloseReason::get(9));
2069 assert_eq!((CloseReason::Unknown, 99), CloseReason::get(99));
2070 }
2071
2072 #[test]
2073 fn test_link_protocol_version_3_boundary() {
2074 let protocol = LinkProtocol::new(3);
2075 assert_eq!(Size::Short, protocol.circ_id_size);
2076 assert_eq!(0x01, protocol.first_circ_id);
2077
2078 let protocol = LinkProtocol::new(4);
2079 assert_eq!(Size::Long, protocol.circ_id_size);
2080 assert_eq!(0x80000000, protocol.first_circ_id);
2081 }
2082
2083 #[test]
2084 fn test_link_specifier_ipv4_wrong_size() {
2085 let data = b"\x00\x04\x01\x02\x03\x04";
2086 let result = LinkSpecifier::pop(data);
2087 assert!(result.is_err());
2088 }
2089
2090 #[test]
2091 fn test_link_specifier_ipv6_wrong_size() {
2092 let data = b"\x01\x10&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01";
2093 let result = LinkSpecifier::pop(data);
2094 assert!(result.is_err());
2095 }
2096
2097 #[test]
2098 fn test_link_specifier_fingerprint_wrong_size() {
2099 let data = b"\x02\x10CCCCCCCCCCCCCCCC";
2100 let result = LinkSpecifier::pop(data);
2101 assert!(result.is_err());
2102 }
2103
2104 #[test]
2105 fn test_link_specifier_ed25519_wrong_size() {
2106 let data = b"\x03\x10CCCCCCCCCCCCCCCC";
2107 let result = LinkSpecifier::pop(data);
2108 assert!(result.is_err());
2109 }
2110}