From 164717e19649cf988abfc716687cf675e5a06bf4 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 10 May 2023 13:07:35 -0400 Subject: [PATCH] linkspec::verbatim: wrapper to give a CircTarget a new set of LinkSpecs --- crates/tor-linkspec/Cargo.toml | 3 +- crates/tor-linkspec/src/lib.rs | 2 + crates/tor-linkspec/src/verbatim.rs | 109 ++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 crates/tor-linkspec/src/verbatim.rs diff --git a/crates/tor-linkspec/Cargo.toml b/crates/tor-linkspec/Cargo.toml index e6d0ff0d9..8113fc17d 100644 --- a/crates/tor-linkspec/Cargo.toml +++ b/crates/tor-linkspec/Cargo.toml @@ -14,9 +14,10 @@ repository = "https://gitlab.torproject.org/tpo/core/arti.git/" [features] default = [] full = ["pt-client"] -experimental = ["decode"] +experimental = ["decode", "verbatim"] pt-client = [] decode = [] +verbatim = [] [dependencies] base64ct = "1.5.1" diff --git a/crates/tor-linkspec/src/lib.rs b/crates/tor-linkspec/src/lib.rs index f4b2b0204..8298b0538 100644 --- a/crates/tor-linkspec/src/lib.rs +++ b/crates/tor-linkspec/src/lib.rs @@ -45,6 +45,8 @@ mod ls; mod owned; mod traits; mod transport; +#[cfg(feature = "verbatim")] +pub mod verbatim; pub use ids::{ by_id::{ByRelayIds, ByRelayIdsError}, diff --git a/crates/tor-linkspec/src/verbatim.rs b/crates/tor-linkspec/src/verbatim.rs new file mode 100644 index 000000000..36e8d9e15 --- /dev/null +++ b/crates/tor-linkspec/src/verbatim.rs @@ -0,0 +1,109 @@ +//! Wrappers for using a CircTarget with a verbatim list of +//! [link specifiers](EncodedLinkSpec). + +use crate::{ChanTarget, CircTarget, EncodedLinkSpec, HasAddrs, HasChanMethod, HasRelayIds}; + +/// A wrapper around an underlying [`CircTarget`] that provides a user-specified +/// list of [link specifiers](EncodedLinkSpec). +/// +/// Onion services and their clients use this type of target when telling a +/// relay to extend a circuit to a target relay (an introduction point or +/// rendezvous point) chosen by some other party. +pub struct VerbatimLinkSpecCircTarget { + /// The underlying CircTarget + target: T, + /// The link specifiers to provide. + linkspecs: Vec, +} + +impl VerbatimLinkSpecCircTarget { + /// Construct a new `VerbatimLinkSpecCircTarget` to wrap an underlying + /// `CircTarget` object, and provide it with a new set of encoded link + /// specifiers that will be used when telling a relay to extend to this + /// node. + /// + /// Note that nothing here will check that `linkspecs` is sufficient to + /// actually connect to the chosen target, or to any target at all. It is + /// the caller's responsibility to choose a valid set of link specifiers. + pub fn new(target: T, linkspecs: Vec) -> Self { + Self { target, linkspecs } + } +} + +// Now, the delegation functions. All of these are simple delegations to +// self.target, except for `CircTarget::linkspecs` with returns self.linkspecs. + +impl HasRelayIds for VerbatimLinkSpecCircTarget { + fn identity(&self, key_type: crate::RelayIdType) -> Option> { + self.target.identity(key_type) + } +} +impl HasAddrs for VerbatimLinkSpecCircTarget { + fn addrs(&self) -> &[std::net::SocketAddr] { + self.target.addrs() + } +} +impl HasChanMethod for VerbatimLinkSpecCircTarget { + fn chan_method(&self) -> crate::ChannelMethod { + self.target.chan_method() + } +} +impl ChanTarget for VerbatimLinkSpecCircTarget {} +impl CircTarget for VerbatimLinkSpecCircTarget { + fn linkspecs(&self) -> tor_bytes::EncodeResult> { + Ok(self.linkspecs.clone()) + } + + fn ntor_onion_key(&self) -> &tor_llcrypto::pk::curve25519::PublicKey { + self.target.ntor_onion_key() + } + + fn protovers(&self) -> &tor_protover::Protocols { + self.target.protovers() + } +} + +#[cfg(test)] +mod test { + // @@ begin test lint list maintained by maint/add_warning @@ + #![allow(clippy::bool_assert_comparison)] + #![allow(clippy::clone_on_copy)] + #![allow(clippy::dbg_macro)] + #![allow(clippy::print_stderr)] + #![allow(clippy::print_stdout)] + #![allow(clippy::single_char_pattern)] + #![allow(clippy::unwrap_used)] + #![allow(clippy::unchecked_duration_subtraction)] + //! + + use crate::OwnedCircTarget; + + use super::*; + #[test] + fn verbatim_linkspecs() { + let mut builder = OwnedCircTarget::builder(); + builder + .chan_target() + .addrs(vec!["127.0.0.1:11".parse().unwrap()]) + .ed_identity([42; 32].into()) + .rsa_identity([45; 20].into()); + let inner = builder + .ntor_onion_key([99; 32].into()) + .protocols("FlowCtrl=7".parse().unwrap()) + .build() + .unwrap(); + let weird_linkspecs = vec![EncodedLinkSpec::new( + 77.into(), + b"mysterious whisper".to_vec(), + )]; + let wrapped = VerbatimLinkSpecCircTarget::new(inner.clone(), weird_linkspecs.clone()); + + assert_eq!(wrapped.addrs(), inner.addrs()); + assert!(wrapped.same_relay_ids(&inner)); + assert_eq!(wrapped.ntor_onion_key(), inner.ntor_onion_key()); + assert_eq!(wrapped.protovers(), inner.protovers()); + + assert_ne!(inner.linkspecs().unwrap(), weird_linkspecs); + assert_eq!(wrapped.linkspecs().unwrap(), weird_linkspecs); + } +}