Commit 9abad8a2 authored by Nick Mathewson's avatar Nick Mathewson 🦀
Browse files

linkspec: Define owned variants of ChanTarget and CircTarget.

parent 62192f3a
Loading
Loading
Loading
Loading
+5 −64
Original line number Diff line number Diff line
@@ -2,13 +2,12 @@

use crate::Error;

use tor_linkspec::ChanTarget;
use tor_linkspec::{ChanTarget, OwnedChanTarget};
use tor_llcrypto::pk;
use tor_rtcompat::{tls::TlsConnector, Runtime, TlsProvider};

use async_trait::async_trait;
use futures::task::SpawnExt;
use std::net::SocketAddr;
use std::sync::Arc;

/// TLS-based channel builder.
@@ -36,7 +35,7 @@ impl<R: Runtime> ChanBuilder<R> {
#[async_trait]
impl<R: Runtime> crate::mgr::ChannelFactory for ChanBuilder<R> {
    type Channel = tor_proto::channel::Channel;
    type BuildSpec = TargetInfo;
    type BuildSpec = OwnedChanTarget;

    async fn build_channel(&self, target: &Self::BuildSpec) -> crate::Result<Arc<Self::Channel>> {
        use tor_rtcompat::SleepProviderExt;
@@ -54,7 +53,7 @@ impl<R: Runtime> ChanBuilder<R> {
    /// As build_channel, but don't include a timeout.
    async fn build_channel_notimeout(
        &self,
        target: &TargetInfo,
        target: &OwnedChanTarget,
    ) -> crate::Result<Arc<tor_proto::channel::Channel>> {
        use tor_proto::channel::ChannelBuilder;
        use tor_rtcompat::tls::CertifiedConn;
@@ -107,47 +106,6 @@ impl crate::mgr::AbstractChannel for tor_proto::channel::Channel {
    }
}

/// TargetInfo is a summary of a [`ChanTarget`] that we can pass to
/// [`ChanBuilder`].
///
/// This is a separate type since we can't declare ChanBuilder as having
/// a parameterized method in today's Rust.
#[derive(Debug, Clone)]
pub(crate) struct TargetInfo {
    /// Copy of the addresses from the underlying ChanTarget.
    addrs: Vec<SocketAddr>,
    /// Copy of the ed25519 id from the underlying ChanTarget.
    ed_identity: pk::ed25519::Ed25519Identity,
    /// Copy of the rsa id from the underlying ChanTarget.
    rsa_identity: pk::rsa::RsaIdentity,
}

impl ChanTarget for TargetInfo {
    fn addrs(&self) -> &[SocketAddr] {
        &self.addrs[..]
    }
    fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity {
        &self.ed_identity
    }
    fn rsa_identity(&self) -> &pk::rsa::RsaIdentity {
        &self.rsa_identity
    }
}

impl TargetInfo {
    /// Construct a TargetInfo from a given ChanTarget.
    pub(crate) fn from_chan_target<C>(target: &C) -> Self
    where
        C: ChanTarget + ?Sized,
    {
        TargetInfo {
            addrs: target.addrs().to_vec(),
            ed_identity: *target.ed_identity(),
            rsa_identity: *target.rsa_identity(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
@@ -157,25 +115,12 @@ mod test {
    };
    use pk::ed25519::Ed25519Identity;
    use pk::rsa::RsaIdentity;
    use std::net::SocketAddr;
    use std::time::{Duration, SystemTime};
    use tor_proto::channel::Channel;
    use tor_rtcompat::{test_with_runtime, TcpListener};
    use tor_rtmock::{io::LocalStream, net::MockNetwork, MockSleepRuntime};

    #[test]
    fn targetinfo() {
        let ti = TargetInfo {
            addrs: vec!["127.0.0.1:11".parse().unwrap()],
            ed_identity: [42; 32].into(),
            rsa_identity: [45; 20].into(),
        };

        let ti2 = TargetInfo::from_chan_target(&ti);
        assert_eq!(ti.addrs, ti2.addrs);
        assert_eq!(ti.ed_identity, ti2.ed_identity);
        assert_eq!(ti.rsa_identity, ti2.rsa_identity);
    }

    // Make sure that the builder can build a real channel.  To test
    // this out, we set up a listener that pretends to have the right
    // IP, fake the current time, and use a canned response from
@@ -188,11 +133,7 @@ mod test {
        let rsa: RsaIdentity = msgs::RSA_ID.into();
        let client_addr = "192.0.2.17".parse().unwrap();
        let tls_cert = msgs::X509_CERT.into();
        let target = TargetInfo {
            addrs: vec![orport],
            ed_identity: ed,
            rsa_identity: rsa,
        };
        let target = OwnedChanTarget::new(vec![orport], ed, rsa);
        let now = SystemTime::UNIX_EPOCH + Duration::new(msgs::NOW, 0);

        test_with_runtime(|rt| async move {
+1 −1
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ impl<R: Runtime> ChanMgr<R> {
    /// or fail depending on its outcome.
    pub async fn get_or_launch<T: ChanTarget + ?Sized>(&self, target: &T) -> Result<Arc<Channel>> {
        let ed_identity = target.ed_identity();
        let targetinfo = builder::TargetInfo::from_chan_target(target);
        let targetinfo = target.to_owned();

        let chan = self.mgr.get_or_launch(*ed_identity, targetinfo).await?;
        // Double-check the match to make sure that the RSA identity is
+2 −0
Original line number Diff line number Diff line
@@ -58,7 +58,9 @@
#![warn(clippy::unseparated_literal_suffix)]

mod ls;
mod owned;
mod traits;

pub use ls::LinkSpec;
pub use owned::{OwnedChanTarget, OwnedCircTarget};
pub use traits::{ChanTarget, CircTarget};
+125 −0
Original line number Diff line number Diff line
//! Owned variants of [`ChanTarget`] and [`CircTarget`].

use std::net::SocketAddr;
use tor_llcrypto::pk;

use crate::{ChanTarget, CircTarget};

/// OwnedChanTarget is a summary of a [`ChanTarget`] that owns all of its
/// members.
#[derive(Debug, Clone)]
pub struct OwnedChanTarget {
    /// Copy of the addresses from the underlying ChanTarget.
    addrs: Vec<SocketAddr>,
    /// Copy of the ed25519 id from the underlying ChanTarget.
    ed_identity: pk::ed25519::Ed25519Identity,
    /// Copy of the rsa id from the underlying ChanTarget.
    rsa_identity: pk::rsa::RsaIdentity,
}

impl ChanTarget for OwnedChanTarget {
    fn addrs(&self) -> &[SocketAddr] {
        &self.addrs[..]
    }
    fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity {
        &self.ed_identity
    }
    fn rsa_identity(&self) -> &pk::rsa::RsaIdentity {
        &self.rsa_identity
    }
}

impl OwnedChanTarget {
    /// Construct a new OwnedChanTarget from its parts.
    // TODO: Put this function behind a feature.
    pub fn new(
        addrs: Vec<SocketAddr>,
        ed_identity: pk::ed25519::Ed25519Identity,
        rsa_identity: pk::rsa::RsaIdentity,
    ) -> Self {
        Self {
            addrs,
            ed_identity,
            rsa_identity,
        }
    }

    /// Construct a OwnedChanTarget from a given ChanTarget.
    pub fn from_chan_target<C>(target: &C) -> Self
    where
        C: ChanTarget + ?Sized,
    {
        OwnedChanTarget {
            addrs: target.addrs().to_vec(),
            ed_identity: *target.ed_identity(),
            rsa_identity: *target.rsa_identity(),
        }
    }
}

/// OwnedCircTarget is a summary of a [`CircTarget`] that owns all its
/// members.
#[derive(Debug, Clone)]
pub struct OwnedCircTarget {
    /// The fields from this object when considered as a ChanTarget.
    chan_target: OwnedChanTarget,
    /// The ntor key to use when extending to this CircTarget
    ntor_onion_key: pk::curve25519::PublicKey,
    /// The subprotocol versions that this CircTarget supports.
    protovers: tor_protover::Protocols,
}

impl OwnedCircTarget {
    /// Construct an OwnedCircTarget from a given CircTarget.
    pub fn from_circ_target<C>(target: &C) -> Self
    where
        C: CircTarget + ?Sized,
    {
        OwnedCircTarget {
            chan_target: OwnedChanTarget::from_chan_target(target),
            ntor_onion_key: *target.ntor_onion_key(),
            // TODO: I don't like having to clone here.  Our underlying
            // protovers parsing uses an Arc, IIRC.  Can we expose that here?
            protovers: target.protovers().clone(),
        }
    }
}

impl ChanTarget for OwnedCircTarget {
    fn addrs(&self) -> &[SocketAddr] {
        self.chan_target.addrs()
    }
    fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity {
        self.chan_target.ed_identity()
    }
    fn rsa_identity(&self) -> &pk::rsa::RsaIdentity {
        self.chan_target.rsa_identity()
    }
}

impl CircTarget for OwnedCircTarget {
    fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey {
        &self.ntor_onion_key
    }
    fn protovers(&self) -> &tor_protover::Protocols {
        &self.protovers
    }
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn targetinfo() {
        let ti = OwnedChanTarget::new(
            vec!["127.0.0.1:11".parse().unwrap()],
            [42; 32].into(),
            [45; 20].into(),
        );

        let ti2 = OwnedChanTarget::from_chan_target(&ti);
        assert_eq!(ti.addrs(), ti2.addrs());
        assert_eq!(ti.ed_identity(), ti2.ed_identity());
        assert_eq!(ti.rsa_identity(), ti2.rsa_identity());
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -27,6 +27,12 @@ pub trait ChanTarget {
    }
    /// 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.