//! Declare traits to be implemented by types that describe a place //! that Tor can connect to, directly or indirectly. use std::net::SocketAddr; use tor_llcrypto::pk; use std::convert::TryInto; /// Information about a Tor relay used to connect to it. /// /// Anything that implements 'ChanTarget' can be used as the /// identity of a relay for the purposes of launching a new /// channel. pub trait ChanTarget { /// Return the addresses at which you can connect to this relay // TODO: This is a questionable API. I'd rather return an iterator // of addresses or references to addresses, but both of those options // make defining the right associated types rather tricky. fn addrs(&self) -> &[SocketAddr]; /// Return the ed25519 identity for this relay. fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity; /// Return the ed25519 identity key for this relay, if it is valid. /// /// This can be costly. fn ed_identity_key(&self) -> Option { self.ed_identity().try_into().ok() } /// Return the RSA identity for this relay. fn rsa_identity(&self) -> &pk::rsa::RsaIdentity; /// Return a new [`crate::OwnedChanTarget`] containing a copy /// of the information in this `ChanTarget`. fn to_owned(&self) -> crate::OwnedChanTarget { crate::OwnedChanTarget::from_chan_target(self) } } /// Information about a Tor relay used to extend a circuit to it. /// /// Anything that implements 'CircTarget' can be used as the /// identity of a relay for the purposes of extending a circuit. pub trait CircTarget: ChanTarget { /// Return a new vector of link specifiers for this relay. // TODO: This is a questionable API. I'd rather return an iterator // of link specifiers, but that's not so easy to do, since it seems // doing so correctly would require default associated types. fn linkspecs(&self) -> Vec { let mut result = vec![(*self.ed_identity()).into(), (*self.rsa_identity()).into()]; for addr in self.addrs().iter() { result.push(addr.into()); } result } /// Return the ntor onion key for this relay fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey; /// Return the subprotocols implemented by this relay. fn protovers(&self) -> &tor_protover::Protocols; } #[cfg(test)] mod test { use super::*; use hex_literal::hex; use std::net::IpAddr; use tor_llcrypto::pk; struct Example { addrs: Vec, ed_id: pk::ed25519::Ed25519Identity, rsa_id: pk::rsa::RsaIdentity, ntor: pk::curve25519::PublicKey, pv: tor_protover::Protocols, } impl ChanTarget for Example { fn addrs(&self) -> &[SocketAddr] { &self.addrs[..] } fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity { &self.ed_id } fn rsa_identity(&self) -> &pk::rsa::RsaIdentity { &self.rsa_id } } impl CircTarget for Example { fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey { &self.ntor } fn protovers(&self) -> &tor_protover::Protocols { &self.pv } } #[test] fn test_linkspecs() { let ex = Example { addrs: vec![ "127.0.0.1:99".parse::().unwrap(), "[::1]:909".parse::().unwrap(), ], ed_id: pk::ed25519::PublicKey::from_bytes(&hex!( "fc51cd8e6218a1a38da47ed00230f058 0816ed13ba3303ac5deb911548908025" )) .unwrap() .into(), rsa_id: pk::rsa::RsaIdentity::from_bytes(&hex!( "1234567890abcdef12341234567890abcdef1234" )) .unwrap(), ntor: pk::curve25519::PublicKey::from(hex!( "e6db6867583030db3594c1a424b15f7c 726624ec26b3353b10a903a6d0ab1c4c" )), pv: tor_protover::Protocols::default(), }; let specs = ex.linkspecs(); assert_eq!(4, specs.len()); use crate::ls::LinkSpec; assert_eq!( specs[0], LinkSpec::Ed25519Id( pk::ed25519::PublicKey::from_bytes(&hex!( "fc51cd8e6218a1a38da47ed00230f058 0816ed13ba3303ac5deb911548908025" )) .unwrap() .into() ) ); assert_eq!( specs[1], LinkSpec::RsaId( pk::rsa::RsaIdentity::from_bytes(&hex!("1234567890abcdef12341234567890abcdef1234")) .unwrap() ) ); assert_eq!( specs[2], LinkSpec::OrPort("127.0.0.1".parse::().unwrap(), 99) ); assert_eq!( specs[3], LinkSpec::OrPort("::1".parse::().unwrap(), 909) ); } }