Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

transports/onion: Add dial-only implementation of Transport #2899

Closed
wants to merge 66 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
ecd352b
Initial commit on Onion transport for libp2p
umgefahren Sep 13, 2022
ca954bf
Added tests, comments and mate implementation somewhat usesable
umgefahren Sep 13, 2022
59e4792
simplified, streamlined and added an example
umgefahren Sep 13, 2022
f69a566
simplified, streamlined and added an example
umgefahren Sep 13, 2022
6cd8ce0
Added some traits
umgefahren Sep 13, 2022
ab0197e
Added cargo fmt changes
umgefahren Sep 13, 2022
0c31c37
fixed typo
umgefahren Sep 13, 2022
9380b18
implemented suggestions
umgefahren Sep 14, 2022
3dabad1
implemented suggestions
umgefahren Sep 14, 2022
cd9ff90
Merge branch 'master' into add-onion
umgefahren Sep 19, 2022
0c7298c
Addressed latest issues
umgefahren Sep 19, 2022
e342500
Merge branch 'add-onion' of github.com:umgefahren/rust-libp2p into ad…
umgefahren Sep 19, 2022
d88af2e
fixed test failure
umgefahren Sep 19, 2022
0680655
Ran cargo fmt
umgefahren Sep 19, 2022
e04869a
Implemented suggested changes
umgefahren Sep 20, 2022
e7db75f
Small module doc
umgefahren Sep 20, 2022
c6335b5
compiles again on wasm32
umgefahren Sep 20, 2022
8c20c30
Refactor multiaddress parsing to avoid clones
thomaseizinger Sep 21, 2022
b6b2aac
Apply suggestions from code review
umgefahren Sep 21, 2022
9d2d94c
renamed stuff
umgefahren Sep 21, 2022
4076338
corrected issues of previous commit an implemented all recently reque…
umgefahren Sep 21, 2022
bf9df0a
formatted
umgefahren Sep 21, 2022
548a815
Apply suggestions from code review
umgefahren Sep 28, 2022
307f19c
Added license headers and added to README.md
umgefahren Sep 28, 2022
6f4bca5
Merge branch 'master' into add-onion
umgefahren Sep 28, 2022
96d0bf9
Merge branch 'master' into add-onion
umgefahren Oct 3, 2022
03ba6e7
addressed todos by @thomaseizinger
umgefahren Oct 3, 2022
e6a51c0
Remove `cargo-deny` exception
thomaseizinger Oct 4, 2022
8de49ca
Remove unnecessary empty lines
thomaseizinger Oct 4, 2022
1492557
Merge `use` statements into one block
thomaseizinger Oct 4, 2022
402835d
Make use of link in changelog
thomaseizinger Oct 4, 2022
b292cd0
Consistently reference `Pin` with FQP to avoid import
thomaseizinger Oct 4, 2022
85f6eb6
Update `arti` to latest version
thomaseizinger Oct 4, 2022
38ba200
Sort dependencies alphabetically
thomaseizinger Oct 4, 2022
077ab94
Use link reference in CHANGELOG.md
thomaseizinger Oct 4, 2022
d57fe41
Fix compile errors
thomaseizinger Oct 4, 2022
389ff09
Merge branch 'master' into add-onion
thomaseizinger Oct 4, 2022
ac6b9a8
Merge branch 'master' into add-onion
umgefahren Oct 4, 2022
0a89bef
Merge branch 'master' into add-onion
umgefahren Oct 4, 2022
bd7f8ac
Really enable all features in full
umgefahren Oct 4, 2022
86a511c
Merge branch 'master' into add-onion
umgefahren Oct 5, 2022
49f0c79
Merge branch 'master' into add-onion
umgefahren Oct 10, 2022
f834d9e
Adjusted example to match the ping example
umgefahren Oct 10, 2022
1a5668b
Fix formatting
thomaseizinger Oct 11, 2022
2fa5162
Merge branch 'master' into add-onion
umgefahren Oct 14, 2022
1d1a219
Merge branch 'master' into add-onion
umgefahren Oct 18, 2022
9bcd2be
Changed CHANGELOG.md entry
umgefahren Oct 18, 2022
65bc267
Update CHANGELOG.md
umgefahren Oct 19, 2022
40765c6
Updated Cargo.toml responding to the requested changes
umgefahren Oct 19, 2022
1f692de
Corrected error in the feature flag
umgefahren Oct 19, 2022
76ed916
Fixed issues with featues
umgefahren Oct 19, 2022
9332ee3
Alphabetically sort feature list
thomaseizinger Oct 19, 2022
c09fa80
Alphabetically sort dependency list
thomaseizinger Oct 19, 2022
285bdc0
Update transports/onion/Cargo.toml
umgefahren Oct 20, 2022
5c908a6
Merge branch 'master' into add-onion
umgefahren Oct 20, 2022
d2c6256
Changed to alpha version.
umgefahren Oct 20, 2022
9b4fce9
Merge branch 'master' into add-onion
umgefahren Oct 21, 2022
62d093b
Merge branch 'master' into add-onion
mxinden Oct 21, 2022
25ea701
Merge branch 'master' into add-onion
thomaseizinger Oct 24, 2022
7865af7
Fixed issue with Cargo.toml
umgefahren Oct 25, 2022
37f170b
Merge master into add-onion
umgefahren Oct 25, 2022
dd5b8b7
Added type alias for DataStream and removed custom doc(cfg( in order …
umgefahren Oct 25, 2022
d4c6ff4
Merge branch 'master' into add-onion
umgefahren Oct 31, 2022
6771e93
Merge branch 'master' into add-onion
umgefahren Nov 9, 2022
d236989
Merge branch 'master' into add-onion
umgefahren Nov 18, 2022
4f72d3c
Made compileable again
umgefahren Nov 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/ping-onion.rs
Expand Up @@ -61,7 +61,7 @@ async fn onion_transport(
tcp::GenTcpConfig::new().nodelay(true),
))
.await?;
let onion = onion::OnionClient::from_builder(onion::OnionClient::builder())?;
let onion = onion::OnionClient::from_builder(onion::OnionClient::builder(), false)?;
println!("bootstrapping...");
onion.bootstrap().await?;
println!("bootstrapped!");
Expand Down
52 changes: 49 additions & 3 deletions transports/onion/src/address.rs
@@ -1,13 +1,13 @@
use std::net::{IpAddr, SocketAddr};

use arti_client::{TorAddr, TorAddrError};
use arti_client::{IntoTorAddr, TorAddr, TorAddrError};
use libp2p_core::{multiaddr::Protocol, Multiaddr};

fn try_extract_socket_addr(mutliaddr: &Multiaddr) -> Result<SocketAddr, TorAddrError> {
fn try_extract_socket_addr(multiaddr: &Multiaddr) -> Result<SocketAddr, TorAddrError> {
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
let mut ip_4 = None;
let mut ip_6 = None;
let mut tcp_port_opt = None;
for e in mutliaddr.iter() {
for e in multiaddr.iter() {
match e {
Protocol::Ip4(a) => {
ip_4 = Some(IpAddr::V4(a));
Expand All @@ -32,3 +32,49 @@ pub(super) fn dangerous_extract_tor_address(
let socket_addr = try_extract_socket_addr(multiaddr)?;
TorAddr::dangerously_from(socket_addr)
}

macro_rules! try_convert_to_tor_addr {
($dns:ident, $tcp_port:ident, $tor_addr_error:ident) => {
if let Some(dns_s) = $dns {
match (dns_s.as_ref(), $tcp_port).into_tor_addr() {
Ok(tor_addr) => return Ok(tor_addr),
Err(e) => $tor_addr_error = Some(e),
}
}
};
}

pub(super) fn safe_extract_tor_address(multiaddr: &Multiaddr) -> Result<TorAddr, TorAddrError> {
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
let mut dns = None;
let mut dns_4 = None;
let mut dns_6 = None;
let mut dns_addr = None;
let mut tcp_port_opt = None;
for e in multiaddr.iter() {
match e {
Protocol::Dns(s) => {
dns = Some(s);
}
Protocol::Dns4(s) => {
dns_4 = Some(s);
}
Protocol::Dns6(s) => {
dns_6 = Some(s);
}
Protocol::Dnsaddr(s) => {
dns_addr = Some(s);
}
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
Protocol::Tcp(p) => {
tcp_port_opt = Some(p);
}
_ => {}
}
}
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
let tcp_port = tcp_port_opt.ok_or(TorAddrError::NoPort)?;
let mut tor_addr_error = None;
try_convert_to_tor_addr!(dns, tcp_port, tor_addr_error);
try_convert_to_tor_addr!(dns_4, tcp_port, tor_addr_error);
try_convert_to_tor_addr!(dns_6, tcp_port, tor_addr_error);
try_convert_to_tor_addr!(dns_addr, tcp_port, tor_addr_error);
Err(tor_addr_error.unwrap_or(TorAddrError::InvalidHostname))
}
110 changes: 90 additions & 20 deletions transports/onion/src/lib.rs
@@ -1,14 +1,15 @@
#![doc(html_logo_url = "https://libp2p.io/img/logo_small.png")]
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
#![doc(html_favicon_url = "https://libp2p.io/img/favicon.png")]
#![cfg_attr(docsrs, feature(doc_cfg))]

use std::pin::Pin;
use std::sync::Arc;

use address::dangerous_extract_tor_address;
use address::{dangerous_extract_tor_address, safe_extract_tor_address};
use arti_client::{TorAddrError, TorClient, TorClientBuilder};
use futures::{future::BoxFuture, FutureExt};
use libp2p_core::{transport::TransportError, Multiaddr, Transport};
use tor_rtcompat::PreferredRuntime;
use tor_rtcompat::Runtime;

mod address;
mod provider;
Expand All @@ -22,37 +23,95 @@ pub enum OnionError {
AddrErr(#[from] TorAddrError),
#[error("error in arti")]
ArtiErr(#[from] arti_client::Error),
#[error("onion services are not implented yet, since arti doesn't support it. (awaiting Arti 1.2.0)")]
OnionServiceUnimplemented,
}

#[derive(Clone)]
pub struct OnionClient {
pub struct OnionClient<R: Runtime> {
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
// client is in an Arc, because wihtout it the Transport::Dial method can't be implemented,
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
// due to lifetime issues. With the, eventual, stabilization of static async traits this issue
// will be resolved.
client: Arc<TorClient<PreferredRuntime>>,
client: Arc<TorClient<R>>,
safe_mode: bool,
}

pub type OnionBuilder = TorClientBuilder<PreferredRuntime>;
pub type OnionBuilder<R> = TorClientBuilder<R>;

impl OnionClient {
impl<R: Runtime> OnionClient<R> {
#[inline]
pub fn builder() -> OnionBuilder {
TorClient::builder()
pub fn from_builder(builder: OnionBuilder<R>, safe_mode: bool) -> Result<Self, OnionError> {
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
let client = Arc::new(builder.create_unbootstrapped()?);
Ok(Self { client, safe_mode })
}

#[inline]
pub fn from_builder(builder: OnionBuilder) -> Result<Self, OnionError> {
let client = Arc::new(builder.create_unbootstrapped()?);
Ok(Self { client })
pub fn is_safe_mode(&self) -> bool {
self.safe_mode
}

#[inline]
pub fn set_safe_mode(&mut self, mode: bool) {
self.safe_mode = mode
}

pub async fn bootstrap(&self) -> Result<(), OnionError> {
Ok(self.client.bootstrap().await?)
self.client.bootstrap().await.map_err(OnionError::ArtiErr)
}
}

#[cfg(all(feature = "native-tls", feature = "async-std"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "native-tls", feature = "async-std"))))]
impl OnionClient<tor_rtcompat::async_std::AsyncStdNativeTlsRuntime> {
pub fn builder() -> OnionBuilder<tor_rtcompat::async_std::AsyncStdNativeTlsRuntime> {
let runtime = tor_rtcompat::async_std::AsyncStdNativeTlsRuntime::current()
.expect("Couldn't get the current async_std native-tls runtime");
TorClient::with_runtime(runtime)
}
}

#[cfg(all(feature = "rustls", feature = "async-std"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "rustls", feature = "async-std"))))]
impl OnionClient<tor_rtcompat::async_std::AsyncStdRustlsRuntime> {
pub fn builder() -> OnionBuilder<tor_rtcompat::async_std::AsyncStdRustlsRuntime> {
let runtime = tor_rtcompat::async_std::AsyncStdRustlsRuntime::current()
.expect("Couldn't get the current async_std rustls runtime");
TorClient::with_runtime(runtime)
}
}

#[cfg(all(feature = "native-tls", feature = "tokio"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "native-tls", feature = "tokio"))))]
impl OnionClient<tor_rtcompat::tokio::TokioNativeTlsRuntime> {
pub fn builder() -> OnionBuilder<tor_rtcompat::tokio::TokioNativeTlsRuntime> {
let runtime = tor_rtcompat::tokio::TokioNativeTlsRuntime::current()
.expect("Couldn't get the current tokio native-tls runtime");
TorClient::with_runtime(runtime)
}
}

#[cfg(all(feature = "rustls", feature = "tokio"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "rustls", feature = "tokio"))))]
impl OnionClient<tor_rtcompat::tokio::TokioRustlsRuntime> {
pub fn builder() -> OnionBuilder<tor_rtcompat::tokio::TokioRustlsRuntime> {
let runtime = tor_rtcompat::tokio::TokioRustlsRuntime::current()
.expect("Couldn't get the current tokio rustls runtime");
TorClient::with_runtime(runtime)
}
}
umgefahren marked this conversation as resolved.
Show resolved Hide resolved

#[cfg(all(feature = "native-tls", feature = "async-std"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "native-tls", feature = "async-std"))))]
pub type OnionAsyncStdNativeTlsClient =
OnionClient<tor_rtcompat::async_std::AsyncStdNativeTlsRuntime>;
#[cfg(all(feature = "rustls", feature = "async-std"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "rustls", feature = "async-std"))))]
pub type OnionAsyncStdRustlsClient = OnionClient<tor_rtcompat::async_std::AsyncStdRustlsRuntime>;
#[cfg(all(feature = "native-tls", feature = "tokio"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "native-tls", feature = "tokio"))))]
pub type OnionTokioNativeTlsClient = OnionClient<tor_rtcompat::tokio::TokioNativeTlsRuntime>;
#[cfg(all(feature = "rustls", feature = "tokio"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "rustls", feature = "tokio"))))]
pub type OnionTokioRustlsClient = OnionClient<tor_rtcompat::tokio::TokioRustlsRuntime>;

#[derive(Debug, Clone, Copy, Default)]
pub struct AlwaysErrorListenerUpgrade;

Expand All @@ -62,11 +121,11 @@ impl core::future::Future for AlwaysErrorListenerUpgrade {
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
core::task::Poll::Ready(Err(OnionError::OnionServiceUnimplemented))
panic!("onion services are not implented yet, since arti doesn't support it. (awaiting Arti 1.2.0)")
}
}

impl Transport for OnionClient {
impl<R: Runtime> Transport for OnionClient<R> {
type Output = OnionStream;
type Error = OnionError;
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
Expand All @@ -91,11 +150,22 @@ impl Transport for OnionClient {
}

fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
let tor_address = dangerous_extract_tor_address(&addr)
.map_err(OnionError::from)
.map_err(TransportError::Other)?;
let tor_address = if !self.safe_mode {
safe_extract_tor_address(&addr).or_else(|_| dangerous_extract_tor_address(&addr))
} else {
safe_extract_tor_address(&addr)
}
.map_err(OnionError::from)
.map_err(TransportError::Other)?;
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
let onion_client = self.client.clone();
Ok(async move { Ok(OnionStream::new(onion_client.connect(tor_address).await?)) }.boxed())
Ok(async move {
onion_client
.connect(tor_address)
.await
.map(OnionStream::new)
.map_err(OnionError::ArtiErr)
}
.boxed())
}

/// Equivalent to `Transport::dial`
Expand Down
88 changes: 0 additions & 88 deletions transports/onion/tests/mod.rs

This file was deleted.