Lines
100 %
Functions
61.11 %
Branches
//! 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<pk::ed25519::PublicKey> {
self.ed_identity().try_into().ok()
}
/// Return the RSA identity for this relay.
fn rsa_identity(&self) -> &pk::rsa::RsaIdentity;
/// 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.
// 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<crate::LinkSpec> {
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 {
#![allow(clippy::unwrap_used)]
use super::*;
use hex_literal::hex;
use std::net::IpAddr;
struct Example {
addrs: Vec<SocketAddr>,
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
/// Return an `Example` object, for use in tests below.
fn example() -> Example {
Example {
addrs: vec![
"127.0.0.1:99".parse::<SocketAddr>().unwrap(),
"[::1]:909".parse::<SocketAddr>().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(),
#[test]
fn test_linkspecs() {
let ex = example();
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!(
.into()
)
);
specs[1],
LinkSpec::RsaId(
pk::rsa::RsaIdentity::from_bytes(&hex!("1234567890abcdef12341234567890abcdef1234"))
specs[2],
LinkSpec::OrPort("127.0.0.1".parse::<IpAddr>().unwrap(), 99)
specs[3],
LinkSpec::OrPort("::1".parse::<IpAddr>().unwrap(), 909)
fn key_accessor() {
// We can get the ed25519 key if it's valid...
let key = ex.ed_identity_key().unwrap();
assert_eq!(&pk::ed25519::Ed25519Identity::from(key), ex.ed_identity());
// Now try an invalid example.
let a = hex!("6d616e79737472696e677361726565646b6579736e6f74746869736f6e654091");
let ex = Example {
ed_id: pk::ed25519::Ed25519Identity::from_bytes(&a).unwrap(),
..ex
};
let key = ex.ed_identity_key();
assert!(key.is_none());