From 36312c532512c7fc386631c84b32827e0964ace6 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 18 Dec 2024 15:04:59 +0800 Subject: [PATCH] Add `TransportType::Onion` Signed-off-by: Eval EXEC --- tentacle/src/runtime/tokio_runtime/mod.rs | 18 ++++++- tentacle/src/transports/mod.rs | 30 ++++++++++- tentacle/src/transports/onion.rs | 62 +++++++++++++++++++++++ tentacle/src/utils.rs | 4 ++ tentacle/src/utils/dns.rs | 4 ++ 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 tentacle/src/transports/onion.rs diff --git a/tentacle/src/runtime/tokio_runtime/mod.rs b/tentacle/src/runtime/tokio_runtime/mod.rs index e74dc4f2..5f6f854c 100644 --- a/tentacle/src/runtime/tokio_runtime/mod.rs +++ b/tentacle/src/runtime/tokio_runtime/mod.rs @@ -1,4 +1,5 @@ pub(crate) mod socks5; +use multiaddr::MultiAddr; use socks5::Socks5Config; pub use tokio::{ net::{TcpListener, TcpStream}, @@ -12,7 +13,7 @@ use socket2::{Domain, Protocol as SocketProtocol, Socket, Type}; use std::os::unix::io::{FromRawFd, IntoRawFd}; #[cfg(windows)] use std::os::windows::io::{FromRawSocket, IntoRawSocket}; -use std::{io, net::SocketAddr}; +use std::{io, net::SocketAddr, str::FromStr}; use tokio::net::TcpSocket as TokioTcp; #[cfg(feature = "tokio-timer")] @@ -147,3 +148,18 @@ pub(crate) async fn connect( } } } + +pub(crate) async fn connect_tor_proxy( + onion_addr: MultiAddr, + tcp_config: TcpSocketConfig, +) -> io::Result { + let proxy_config = tcp_config.proxy_config.ok_or(std::io::Error::other( + "need tor proxy server to connect to onion address", + ))?; + let socks5_config: Socks5Config = super::socks5::parse(&proxy_config.proxy_url)?; + let address = shadowsocks::relay::Address::from_str(onion_addr.to_string().as_str()) + .map_err(|err| std::io::Error::other(err))?; + super::socks5::connect(address, socks5_config) + .await + .map_err(|err| io::Error::other(err)) +} diff --git a/tentacle/src/transports/mod.rs b/tentacle/src/transports/mod.rs index 9078273c..9b3ffe59 100644 --- a/tentacle/src/transports/mod.rs +++ b/tentacle/src/transports/mod.rs @@ -16,6 +16,8 @@ mod browser; #[cfg(not(target_family = "wasm"))] mod memory; #[cfg(not(target_family = "wasm"))] +mod onion; +#[cfg(not(target_family = "wasm"))] mod tcp; #[cfg(not(target_family = "wasm"))] mod tcp_base_listen; @@ -95,6 +97,8 @@ mod os { }; use futures::{prelude::Stream, FutureExt, StreamExt}; + use multiaddr::MultiAddr; + use onion::OnionTransport; use std::{ collections::HashMap, fmt, @@ -162,7 +166,7 @@ mod os { fn listen(self, address: Multiaddr) -> Result { match find_type(&address) { - TransportType::Tcp => { + TransportType::Tcp | TransportType::Onion => { match TcpTransport::from_multi_transport(self, TcpListenMode::Tcp) .listen(address) { @@ -216,6 +220,12 @@ mod os { Err(e) => Err(e), } } + TransportType::Onion => { + match OnionTransport::new(self.timeout, self.tcp_config.tcp).dial(address) { + Ok(res) => Ok(MultiDialFuture::Tcp(res)), + Err(e) => Err(e), + } + } #[cfg(feature = "ws")] TransportType::Ws => { match WsTransport::new(self.timeout, self.tcp_config.ws).dial(address) { @@ -436,6 +446,24 @@ mod os { Ok(res) => res.map_err(Into::into), } } + + /// onion common dial realization + #[inline(always)] + pub async fn onion_dial( + onion_addr: MultiAddr, + tcp_config: TcpSocketConfig, + timeout: Duration, + ) -> Result { + match crate::runtime::timeout( + timeout, + crate::runtime::connect_tor_proxy(onion_addr, tcp_config), + ) + .await + { + Err(_) => Err(TransportErrorKind::Io(io::ErrorKind::TimedOut.into())), + Ok(res) => res.map_err(Into::into), + } + } } #[cfg(target_family = "wasm")] diff --git a/tentacle/src/transports/onion.rs b/tentacle/src/transports/onion.rs new file mode 100644 index 00000000..e924e423 --- /dev/null +++ b/tentacle/src/transports/onion.rs @@ -0,0 +1,62 @@ +use futures::future::ok; +use std::{ + collections::HashMap, future::Future, net::SocketAddr, pin::Pin, sync::Arc, time::Duration, +}; + +#[cfg(feature = "tls")] +use crate::service::TlsConfig; +use crate::{ + multiaddr::Multiaddr, + runtime::TcpStream, + service::config::TcpSocketConfig, + transports::{ + onion_dial, tcp_base_listen::UpgradeMode, Result, TcpListenMode, TransportDial, + TransportFuture, + }, +}; + +/// Onion connect +async fn connect( + onion_address: impl Future>, + timeout: Duration, + tcp_config: TcpSocketConfig, +) -> Result<(Multiaddr, TcpStream)> { + let onion_addr = onion_address.await?; + let stream = onion_dial(onion_addr.clone(), tcp_config, timeout).await?; + Ok((onion_addr, stream)) +} + +/// Onion transport +pub struct OnionTransport { + timeout: Duration, + tcp_config: TcpSocketConfig, + listen_mode: TcpListenMode, + global: Arc>>, + #[cfg(feature = "tls")] + tls_config: TlsConfig, +} + +impl OnionTransport { + pub fn new(timeout: Duration, tcp_config: TcpSocketConfig) -> Self { + Self { + timeout, + tcp_config, + listen_mode: TcpListenMode::Tcp, + global: Arc::new(crate::lock::Mutex::new(Default::default())), + #[cfg(feature = "tls")] + tls_config: Default::default(), + } + } +} + +pub type OnionDialFuture = + TransportFuture> + Send>>>; + +impl TransportDial for OnionTransport { + type DialFuture = OnionDialFuture; + + fn dial(self, address: Multiaddr) -> Result { + let dial = connect(ok(address), self.timeout, self.tcp_config); + Ok(TransportFuture::new(Box::pin(dial))) + } +} diff --git a/tentacle/src/utils.rs b/tentacle/src/utils.rs index a35894ae..1e83b035 100644 --- a/tentacle/src/utils.rs +++ b/tentacle/src/utils.rs @@ -127,6 +127,8 @@ pub enum TransportType { Tls, /// Memory Memory, + /// Onion + Onion, } /// Confirm the transport used by multiaddress @@ -142,6 +144,8 @@ pub fn find_type(addr: &Multiaddr) -> TransportType { Some(TransportType::Tls) } else if let Protocol::Memory(_) = proto { Some(TransportType::Memory) + } else if let Protocol::Onion3(_) = proto { + Some(TransportType::Onion) } else { None } diff --git a/tentacle/src/utils/dns.rs b/tentacle/src/utils/dns.rs index edf39b96..d38e689b 100644 --- a/tentacle/src/utils/dns.rs +++ b/tentacle/src/utils/dns.rs @@ -1,4 +1,5 @@ use futures::FutureExt; +use log::warn; use std::{ borrow::Cow, future::Future, @@ -86,6 +87,9 @@ impl DnsResolver { } TransportType::Ws => address.push(Protocol::Ws), TransportType::Wss => address.push(Protocol::Wss), + TransportType::Onion => { + warn!("Onion transport type should not have dns resolve") + } } if let Some(peer_id) = self.peer_id.take() {