use std::{io, sync::Arc};
use log::*;
use multiaddr::{Multiaddr, Protocol, multiaddr};
use tokio::sync::RwLock;
use crate::{
tor::{HiddenServiceController, TorIdentity},
transports::{SocksTransport, Transport, tcp::TcpInbound},
types::TransportProtocol,
utils::network::supports_ipv6,
};
const LOG_TARGET: &str = "comms::transports::hidden_service_transport";
struct HiddenServiceTransportInner {
socks_transport: Option<SocksTransport>,
hidden_service_ctl: Option<HiddenServiceController>,
}
#[derive(Clone)]
pub struct HiddenServiceTransport<F: Fn(TorIdentity)> {
inner: Arc<RwLock<HiddenServiceTransportInner>>,
after_init: F,
supported_protocols: Vec<TransportProtocol>,
}
impl<F: Fn(TorIdentity)> HiddenServiceTransport<F> {
pub fn new(hidden_service_ctl: HiddenServiceController, after_init: F) -> Self {
let mut supported_protocols = vec![TransportProtocol::Ipv4, TransportProtocol::Onion];
if supports_ipv6() {
supported_protocols.push(TransportProtocol::Ipv6);
}
Self {
inner: Arc::new(RwLock::new(HiddenServiceTransportInner {
socks_transport: None,
hidden_service_ctl: Some(hidden_service_ctl),
})),
after_init,
supported_protocols,
}
}
async fn is_initialized(&self) -> bool {
self.inner.read().await.socks_transport.is_some()
}
async fn initialize(&self, listen_addr: &Multiaddr) -> Result<(TcpInbound, Multiaddr), io::Error> {
let mut inner_mut = self.inner.write().await;
let mut hs_ctl = inner_mut.hidden_service_ctl.take().ok_or(io::Error::other(
"BUG: Hidden service controller not set in transport".to_string(),
))?;
let transport = hs_ctl.initialize_transport().await.map_err(|e| {
error!(
target: LOG_TARGET,
"Error initializing hidden transport service stack{e}"
);
io::Error::other(e.to_string())
})?;
let (inbound, listen_addr) = transport.listen(listen_addr).await?;
inner_mut.socks_transport = Some(transport);
let mut proxied_addr = hs_ctl.proxied_address();
if proxied_addr.ends_with(&multiaddr!(Tcp(0u16))) {
if let Some(Protocol::Tcp(port)) = listen_addr.iter().last() {
proxied_addr.pop();
proxied_addr.push(Protocol::Tcp(port));
}
hs_ctl.set_proxied_addr(&proxied_addr);
}
let hidden_service = hs_ctl.create_hidden_service().await.map_err(|err| {
error!(
target: LOG_TARGET,
"Error creating hidden service: {err}"
);
io::Error::other(err.to_string())
})?;
(self.after_init)(hidden_service.tor_identity().clone());
Ok((inbound, listen_addr))
}
}
#[crate::async_trait]
impl<F: Fn(TorIdentity) + Send + Sync> Transport for HiddenServiceTransport<F> {
type Error = <SocksTransport as Transport>::Error;
type Listener = <SocksTransport as Transport>::Listener;
type Output = <SocksTransport as Transport>::Output;
async fn listen(&self, addr: &Multiaddr) -> Result<(Self::Listener, Multiaddr), Self::Error> {
if self.is_initialized().await {
return Err(io::Error::other(
"BUG: Hidden service transport already initialized".to_string(),
));
}
let (listener, addr) = self.initialize(addr).await?;
Ok((listener, addr))
}
async fn dial(&self, addr: &Multiaddr) -> Result<Self::Output, Self::Error> {
let inner = self.inner.read().await;
let transport = inner.socks_transport.as_ref().ok_or_else(|| {
io::Error::other("BUG: Hidden service transport not initialized before dialling".to_string())
})?;
transport.dial(addr).await
}
fn supported_protocols(&self) -> Vec<TransportProtocol> {
self.supported_protocols.clone()
}
}