mod.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{
  19. io::{self, ErrorKind},
  20. time::Duration,
  21. };
  22. use async_trait::async_trait;
  23. use log::error;
  24. use smol::io::{AsyncRead, AsyncWrite};
  25. use url::Url;
  26. /// TLS upgrade mechanism
  27. pub(crate) mod tls;
  28. /// SOCKS5 proxy client
  29. pub mod socks5;
  30. /// TCP transport
  31. pub(crate) mod tcp;
  32. #[cfg(feature = "p2p-tor")]
  33. /// Tor transport
  34. pub(crate) mod tor;
  35. #[cfg(feature = "p2p-nym")]
  36. /// Nym transport
  37. pub(crate) mod nym;
  38. /// Unix socket transport
  39. pub(crate) mod unix;
  40. /// Dialer variants
  41. #[derive(Debug, Clone)]
  42. pub enum DialerVariant {
  43. /// Plain TCP
  44. Tcp(tcp::TcpDialer),
  45. /// TCP with TLS
  46. TcpTls(tcp::TcpDialer),
  47. #[cfg(feature = "p2p-tor")]
  48. /// Tor
  49. Tor(tor::TorDialer),
  50. #[cfg(feature = "p2p-tor")]
  51. /// Tor with TLS
  52. TorTls(tor::TorDialer),
  53. #[cfg(feature = "p2p-nym")]
  54. /// Nym
  55. Nym(nym::NymDialer),
  56. #[cfg(feature = "p2p-nym")]
  57. /// Nym with TLS
  58. NymTls(nym::NymDialer),
  59. /// Unix socket
  60. Unix(unix::UnixDialer),
  61. }
  62. /// Listener variants
  63. #[derive(Debug, Clone)]
  64. pub enum ListenerVariant {
  65. /// Plain TCP
  66. Tcp(tcp::TcpListener),
  67. /// TCP with TLS
  68. TcpTls(tcp::TcpListener),
  69. #[cfg(feature = "p2p-tor")]
  70. /// Tor
  71. Tor(tor::TorListener),
  72. /// Unix socket
  73. Unix(unix::UnixListener),
  74. }
  75. /// A dialer that is able to transparently operate over arbitrary transports.
  76. pub struct Dialer {
  77. /// The endpoint to connect to
  78. endpoint: Url,
  79. /// The dialer variant (transport protocol)
  80. variant: DialerVariant,
  81. }
  82. macro_rules! enforce_hostport {
  83. ($endpoint:ident) => {
  84. if $endpoint.host_str().is_none() || $endpoint.port().is_none() {
  85. return Err(io::Error::from_raw_os_error(libc::ENETUNREACH))
  86. }
  87. };
  88. }
  89. macro_rules! enforce_abspath {
  90. ($endpoint:ident) => {
  91. if $endpoint.host_str().is_some() || $endpoint.port().is_some() {
  92. return Err(io::Error::from_raw_os_error(libc::ENETUNREACH))
  93. }
  94. if $endpoint.to_file_path().is_err() {
  95. return Err(io::Error::from_raw_os_error(libc::ENETUNREACH))
  96. }
  97. };
  98. }
  99. impl Dialer {
  100. /// Instantiate a new [`Dialer`] with the given [`Url`] and datastore path.
  101. pub async fn new(endpoint: Url, datastore: Option<String>) -> io::Result<Self> {
  102. match endpoint.scheme().to_lowercase().as_str() {
  103. "tcp" => {
  104. // Build a TCP dialer
  105. enforce_hostport!(endpoint);
  106. let variant = tcp::TcpDialer::new(None).await?;
  107. let variant = DialerVariant::Tcp(variant);
  108. Ok(Self { endpoint, variant })
  109. }
  110. "tcp+tls" => {
  111. // Build a TCP dialer wrapped with TLS
  112. enforce_hostport!(endpoint);
  113. let variant = tcp::TcpDialer::new(None).await?;
  114. let variant = DialerVariant::TcpTls(variant);
  115. Ok(Self { endpoint, variant })
  116. }
  117. #[cfg(feature = "p2p-tor")]
  118. "tor" => {
  119. // Build a Tor dialer
  120. enforce_hostport!(endpoint);
  121. let variant = tor::TorDialer::new(datastore).await?;
  122. let variant = DialerVariant::Tor(variant);
  123. Ok(Self { endpoint, variant })
  124. }
  125. #[cfg(feature = "p2p-tor")]
  126. "tor+tls" => {
  127. // Build a Tor dialer wrapped with TLS
  128. enforce_hostport!(endpoint);
  129. let variant = tor::TorDialer::new(datastore).await?;
  130. let variant = DialerVariant::TorTls(variant);
  131. Ok(Self { endpoint, variant })
  132. }
  133. #[cfg(feature = "p2p-nym")]
  134. "nym" => {
  135. // Build a Nym dialer
  136. enforce_hostport!(endpoint);
  137. let variant = nym::NymDialer::new().await?;
  138. let variant = DialerVariant::Nym(variant);
  139. Ok(Self { endpoint, variant })
  140. }
  141. #[cfg(feature = "p2p-nym")]
  142. "nym+tls" => {
  143. // Build a Nym dialer wrapped with TLS
  144. enforce_hostport!(endpoint);
  145. let variant = nym::NymDialer::new().await?;
  146. let variant = DialerVariant::NymTls(variant);
  147. Ok(Self { endpoint, variant })
  148. }
  149. "unix" => {
  150. // Build a Unix socket dialer
  151. enforce_abspath!(endpoint);
  152. let variant = unix::UnixDialer::new().await?;
  153. let variant = DialerVariant::Unix(variant);
  154. Ok(Self { endpoint, variant })
  155. }
  156. x => {
  157. error!("[P2P] Requested unsupported transport: {}", x);
  158. Err(io::Error::from_raw_os_error(libc::ENETUNREACH))
  159. }
  160. }
  161. }
  162. /// Dial an instantiated [`Dialer`]. This creates a connection and returns a stream.
  163. /// The Tor-based Dialer variants can panic: this is intended. There exists validation
  164. /// for hosts and ports in other parts of the codebase. A panic occurring here
  165. /// likely indicates a configuration issue on the part of the user. It is preferable
  166. /// in this case that the user is alerted to this problem via a panic.
  167. pub async fn dial(&self, timeout: Option<Duration>) -> io::Result<Box<dyn PtStream>> {
  168. match &self.variant {
  169. DialerVariant::Tcp(dialer) => {
  170. // NOTE: sockaddr here is an array, can contain both ipv4 and ipv6
  171. let sockaddr = self.endpoint.socket_addrs(|| None)?;
  172. let stream = dialer.do_dial(sockaddr[0], timeout).await?;
  173. Ok(Box::new(stream))
  174. }
  175. DialerVariant::TcpTls(dialer) => {
  176. let sockaddr = self.endpoint.socket_addrs(|| None)?;
  177. let stream = dialer.do_dial(sockaddr[0], timeout).await?;
  178. let tlsupgrade = tls::TlsUpgrade::new().await;
  179. let stream = tlsupgrade.upgrade_dialer_tls(stream).await?;
  180. Ok(Box::new(stream))
  181. }
  182. #[cfg(feature = "p2p-tor")]
  183. DialerVariant::Tor(dialer) => {
  184. let host = self.endpoint.host_str().unwrap();
  185. let port = self.endpoint.port().unwrap();
  186. let stream = dialer.do_dial(host, port, timeout).await?;
  187. Ok(Box::new(stream))
  188. }
  189. #[cfg(feature = "p2p-tor")]
  190. DialerVariant::TorTls(dialer) => {
  191. let host = self.endpoint.host_str().unwrap();
  192. let port = self.endpoint.port().unwrap();
  193. let stream = dialer.do_dial(host, port, timeout).await?;
  194. let tlsupgrade = tls::TlsUpgrade::new().await;
  195. let stream = tlsupgrade.upgrade_dialer_tls(stream).await?;
  196. Ok(Box::new(stream))
  197. }
  198. #[cfg(feature = "p2p-nym")]
  199. DialerVariant::Nym(_dialer) => {
  200. todo!();
  201. }
  202. #[cfg(feature = "p2p-nym")]
  203. DialerVariant::NymTls(_dialer) => {
  204. todo!();
  205. }
  206. DialerVariant::Unix(dialer) => {
  207. let path = match self.endpoint.to_file_path() {
  208. Ok(v) => v,
  209. Err(_) => return Err(io::Error::new(ErrorKind::Unsupported, "Invalid path")),
  210. };
  211. let stream = dialer.do_dial(path).await?;
  212. Ok(Box::new(stream))
  213. }
  214. }
  215. }
  216. /// Return a reference to the `Dialer` endpoint
  217. pub fn endpoint(&self) -> &Url {
  218. &self.endpoint
  219. }
  220. }
  221. /// A listener that is able to transparently listen over arbitrary transports.
  222. pub struct Listener {
  223. /// The address to open the listener on
  224. endpoint: Url,
  225. /// The listener variant (transport protocol)
  226. variant: ListenerVariant,
  227. }
  228. impl Listener {
  229. /// Instantiate a new [`Listener`] with the given [`Url`] and datastore path.
  230. /// Must contain a scheme, host string, and a port.
  231. pub async fn new(endpoint: Url, datastore: Option<String>) -> io::Result<Self> {
  232. match endpoint.scheme().to_lowercase().as_str() {
  233. "tcp" => {
  234. // Build a TCP listener
  235. enforce_hostport!(endpoint);
  236. let variant = tcp::TcpListener::new(1024).await?;
  237. let variant = ListenerVariant::Tcp(variant);
  238. Ok(Self { endpoint, variant })
  239. }
  240. "tcp+tls" => {
  241. // Build a TCP listener wrapped with TLS
  242. enforce_hostport!(endpoint);
  243. let variant = tcp::TcpListener::new(1024).await?;
  244. let variant = ListenerVariant::TcpTls(variant);
  245. Ok(Self { endpoint, variant })
  246. }
  247. #[cfg(feature = "p2p-tor")]
  248. "tor" => {
  249. // Build a Tor Hidden Service listener
  250. enforce_hostport!(endpoint);
  251. let variant = tor::TorListener::new(datastore).await?;
  252. let variant = ListenerVariant::Tor(variant);
  253. Ok(Self { endpoint, variant })
  254. }
  255. "unix" => {
  256. enforce_abspath!(endpoint);
  257. let variant = unix::UnixListener::new().await?;
  258. let variant = ListenerVariant::Unix(variant);
  259. Ok(Self { endpoint, variant })
  260. }
  261. x => {
  262. error!("[P2P] Requested unsupported transport: {}", x);
  263. Err(io::Error::from_raw_os_error(libc::ENETUNREACH))
  264. }
  265. }
  266. }
  267. /// Listen on an instantiated [`Listener`].
  268. /// This will open a socket and return the listener.
  269. pub async fn listen(&self) -> io::Result<Box<dyn PtListener>> {
  270. match &self.variant {
  271. ListenerVariant::Tcp(listener) => {
  272. let sockaddr = self.endpoint.socket_addrs(|| None)?;
  273. let l = listener.do_listen(sockaddr[0]).await?;
  274. Ok(Box::new(l))
  275. }
  276. ListenerVariant::TcpTls(listener) => {
  277. let sockaddr = self.endpoint.socket_addrs(|| None)?;
  278. let l = listener.do_listen(sockaddr[0]).await?;
  279. let tlsupgrade = tls::TlsUpgrade::new().await;
  280. let l = tlsupgrade.upgrade_listener_tcp_tls(l).await?;
  281. Ok(Box::new(l))
  282. }
  283. #[cfg(feature = "p2p-tor")]
  284. ListenerVariant::Tor(listener) => {
  285. let port = self.endpoint.port().unwrap();
  286. let l = listener.do_listen(port).await?;
  287. Ok(Box::new(l))
  288. }
  289. ListenerVariant::Unix(listener) => {
  290. let path = match self.endpoint.to_file_path() {
  291. Ok(v) => v,
  292. Err(_) => return Err(io::Error::new(ErrorKind::Unsupported, "Invalid path")),
  293. };
  294. let l = listener.do_listen(&path).await?;
  295. Ok(Box::new(l))
  296. }
  297. }
  298. }
  299. pub async fn endpoint(&self) -> Url {
  300. match &self.variant {
  301. #[cfg(feature = "p2p-tor")]
  302. ListenerVariant::Tor(listener) => listener.endpoint.lock().await.clone().unwrap(),
  303. _ => self.endpoint.clone(),
  304. }
  305. }
  306. }
  307. /// Wrapper trait for async streams
  308. pub trait PtStream: AsyncRead + AsyncWrite + Unpin + Send {}
  309. impl PtStream for smol::net::TcpStream {}
  310. impl PtStream for futures_rustls::TlsStream<smol::net::TcpStream> {}
  311. #[cfg(feature = "p2p-tor")]
  312. impl PtStream for arti_client::DataStream {}
  313. #[cfg(feature = "p2p-tor")]
  314. impl PtStream for futures_rustls::TlsStream<arti_client::DataStream> {}
  315. impl PtStream for smol::net::unix::UnixStream {}
  316. /// Wrapper trait for async listeners
  317. #[async_trait]
  318. pub trait PtListener: Send + Unpin {
  319. async fn next(&self) -> io::Result<(Box<dyn PtStream>, Url)>;
  320. }