use derive_deftly::{Deftly, define_derive_deftly};
use std::{net::IpAddr, sync::Arc};
use tor_cell::relaycell::msg::AnyRelayMsg;
use tor_error::internal;
use tor_linkspec::{CircTarget, IntoOwnedChanTarget, OwnedChanTarget};
use tor_proto::{
ClockSkew, TargetHop,
circuit::UniqId,
client::circuit::{CircParameters, CircuitBinding, ClientCirc},
client::stream::{DataStream, StreamParameters},
};
use tracing::instrument;
use crate::{Error, Result};
#[cfg(feature = "hs-common")]
use tor_proto::client::circuit::handshake;
define_derive_deftly! {
BaseTunnel for struct:
impl From<tor_proto::ClientTunnel> for $ttype {
fn from(tunnel: tor_proto::ClientTunnel) -> Self {
Self { tunnel: Arc::new(tunnel) }
}
}
impl From<Arc<tor_proto::ClientTunnel>> for $ttype {
fn from(tunnel: Arc<tor_proto::ClientTunnel>) -> Self {
Self { tunnel }
}
}
impl AsRef<tor_proto::ClientTunnel> for $ttype {
fn as_ref(&self) -> &tor_proto::ClientTunnel {
self.tunnel.as_ref()
}
}
impl $ttype {
fn tunnel_ref(&self) -> &Arc<tor_proto::ClientTunnel> {
&self.tunnel
}
pub fn is_closed(&self) -> bool {
self.tunnel_ref().is_closed()
}
pub fn last_hop(&self) -> Result<TargetHop> {
self.tunnel_ref().last_hop()
.map_err(|error| Error::Protocol {
action: "get last hop",
peer: None,
error,
unique_id: Some(self.tunnel.unique_id()),
})
}
pub fn terminate(&self) {
self.tunnel_ref().terminate();
}
pub fn unique_id(&self) -> UniqId {
self.tunnel_ref().unique_id()
}
#[cfg(feature = "send-control-msg")]
pub async fn send_raw_msg(&self, msg: AnyRelayMsg, hop: TargetHop) -> Result<()> {
self.tunnel_ref()
.send_raw_msg(msg, hop)
.await
.map_err(|error| Error::Protocol {
action: "send raw msg",
peer: None,
error,
unique_id: Some(self.tunnel.unique_id()),
})
}
#[cfg_attr(docsrs, doc(cfg(feature = "send-control-msg")))]
#[cfg(feature = "send-control-msg")]
pub async fn start_conversation(&self,
msg: Option<tor_cell::relaycell::msg::AnyRelayMsg>,
reply_handler: impl tor_proto::MsgHandler + Send + 'static,
hop: TargetHop
) -> Result<tor_proto::Conversation<'_>> {
self.tunnel_ref().start_conversation(msg, reply_handler, hop).await
.map_err(|error| Error::Protocol {
action: "start conversation",
peer: None,
error,
unique_id: Some(self.tunnel_ref().unique_id()),
})
}
pub fn wait_for_close(&self) -> impl futures::Future<Output = ()> + Send + Sync + 'static + use<> {
self.tunnel_ref().wait_for_close()
}
}
}
define_derive_deftly! {
SinglePathTunnel for struct:
impl $ttype {
fn circuit(&self) -> Result<&ClientCirc> {
Ok(self.tunnel_ref()
.as_single_circ()
.map_err(|e| internal!("Non single path in a single path tunnel: {}", e))?)
}
pub async fn extend<T: CircTarget>(&self, target: &T, params: CircParameters) -> Result<()> {
self.circuit()?
.extend(target, params)
.await
.map_err(|error| Error::Protocol {
action: "extend tunnel",
peer: Some(target.to_owned().to_logged()),
error,
unique_id: Some(self.tunnel.unique_id()),
})
}
pub fn n_hops(&self) -> Result<usize> {
self.circuit()?.n_hops()
.map_err(|error| Error::Protocol {
action: "get number hops",
peer: None,
error,
unique_id: Some(self.tunnel_ref().unique_id()),
})
}
}
}
#[cfg(feature = "conflux")]
define_derive_deftly! {
MultiPathTunnel for struct:
impl $ttype {
}
}
define_derive_deftly! {
DataTunnel for struct:
impl $ttype {
#[instrument(skip_all, level = "trace")]
pub async fn begin_stream(
&self,
target: &str,
port: u16,
params: Option<StreamParameters>,
) -> Result<DataStream> {
self.tunnel_ref()
.begin_stream(target, port, params)
.await
.map_err(|error| Error::Protocol {
action: "begin stream",
peer: None,
error,
unique_id: Some(self.tunnel.unique_id()),
})
}
}
}
define_derive_deftly! {
DnsTunnel for struct:
impl $ttype {
pub async fn resolve(&self, hostname: &str) -> Result<Vec<IpAddr>> {
self.tunnel_ref()
.resolve(hostname)
.await
.map_err(|error| Error::Protocol {
action: "resolve",
peer: None,
error,
unique_id: Some(self.tunnel.unique_id()),
})
}
pub async fn resolve_ptr(&self, addr: IpAddr) -> Result<Vec<String>> {
self.tunnel_ref()
.resolve_ptr(addr)
.await
.map_err(|error| Error::Protocol {
action: "resolve PTR",
peer: None,
error,
unique_id: Some(self.tunnel.unique_id()),
})
}
}
}
define_derive_deftly! {
DirTunnel for struct:
impl $ttype {
pub async fn begin_dir_stream(&self) -> Result<DataStream> {
self.tunnel_ref().clone()
.begin_dir_stream()
.await
.map_err(|error| Error::Protocol {
action: "begin dir stream",
peer: None,
error,
unique_id: Some(self.tunnel.unique_id()),
})
}
}
}
define_derive_deftly! {
OnionServiceDataTunnel for struct:
impl $ttype {
#[cfg(feature = "hs-common")]
pub async fn extend_virtual(
&self,
protocol: handshake::RelayProtocol,
role: handshake::HandshakeRole,
seed: impl handshake::KeyGenerator,
params: CircParameters,
capabilities: &tor_protover::Protocols,
) -> Result<()> {
self.circuit()?
.extend_virtual(protocol, role, seed, ¶ms, capabilities)
.await
.map_err(|error| Error::Protocol {
action: "extend virtual tunnel",
peer: None,
error,
unique_id: Some(self.tunnel.unique_id()),
})
}
}
}
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, DataTunnel, DnsTunnel, SinglePathTunnel)]
pub struct ClientDataTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, DirTunnel, SinglePathTunnel)]
pub struct ClientDirTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, DataTunnel, OnionServiceDataTunnel, SinglePathTunnel)]
pub struct ClientOnionServiceDataTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, DirTunnel, SinglePathTunnel)]
pub struct ClientOnionServiceDirTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, SinglePathTunnel)]
pub struct ClientOnionServiceIntroTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, DataTunnel, OnionServiceDataTunnel, SinglePathTunnel)]
pub struct ServiceOnionServiceDataTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, DirTunnel, SinglePathTunnel)]
pub struct ServiceOnionServiceDirTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, SinglePathTunnel)]
pub struct ServiceOnionServiceIntroTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
#[cfg(feature = "conflux")]
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, DataTunnel, DnsTunnel, MultiPathTunnel)]
pub struct ClientMultiPathDataTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
#[cfg(feature = "conflux")]
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, DataTunnel, MultiPathTunnel)]
pub struct ClientMultiPathOnionServiceDataTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
#[cfg(feature = "conflux")]
#[derive(Debug, Deftly)]
#[derive_deftly(BaseTunnel, DataTunnel, MultiPathTunnel)]
pub struct ServiceMultiPathOnionServiceDataTunnel {
tunnel: Arc<tor_proto::ClientTunnel>,
}
impl ClientDirTunnel {
pub fn first_hop(&self) -> OwnedChanTarget {
self.tunnel_ref()
.first_hop()
.expect("Bug getting dir tunnel first hop")
}
pub async fn first_hop_clock_skew(&self) -> Result<ClockSkew> {
self.circuit()?
.first_hop_clock_skew()
.await
.map_err(|_| Error::CircCanceled)
}
}
impl ServiceOnionServiceDataTunnel {
#[cfg(feature = "hs-service")]
pub async fn allow_stream_requests<'a, FILT>(
&self,
allow_commands: &'a [tor_cell::relaycell::RelayCmd],
hop: TargetHop,
filter: FILT,
) -> Result<
impl futures::Stream<Item = tor_proto::client::stream::IncomingStream> + use<'a, FILT>,
>
where
FILT: tor_proto::client::stream::IncomingStreamRequestFilter,
{
self.tunnel_ref()
.allow_stream_requests(allow_commands, hop, filter)
.await
.map_err(|error| Error::Protocol {
action: "allow stream requests",
peer: None,
error,
unique_id: Some(self.tunnel.unique_id()),
})
}
}
#[cfg(feature = "hs-service")]
impl ServiceOnionServiceIntroTunnel {
pub async fn binding_key(&self, hop: TargetHop) -> Result<Option<CircuitBinding>> {
let circ = self.circuit()?;
circ.binding_key(hop)
.await
.map_err(|error| Error::Protocol {
action: "binding key",
peer: None,
error,
unique_id: Some(self.tunnel.unique_id()),
})
}
}