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 9 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
16 changes: 15 additions & 1 deletion Cargo.toml
Expand Up @@ -35,6 +35,9 @@ default = [
"wasm-ext",
"websocket",
"yamux",
"onion",
"onion-async-std",
"onion-native-tls"
]

autonat = ["dep:libp2p-autonat"]
Expand Down Expand Up @@ -68,6 +71,11 @@ yamux = ["dep:libp2p-yamux"]
secp256k1 = ["libp2p-core/secp256k1"]
rsa = ["libp2p-core/rsa"]
serde = ["libp2p-core/serde", "libp2p-kad?/serde", "libp2p-gossipsub?/serde"]
onion = ["dep:libp2p-onion"]
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
onion-async-std = ["libp2p-onion?/async-std"]
onion-tokio = ["libp2p-onion?/tokio"]
onion-native-tls = ["libp2p-onion?/native-tls"]
onion-rustls = ["libp2p-onion?/rustls"]

[package.metadata.docs.rs]
all-features = true
Expand Down Expand Up @@ -112,6 +120,7 @@ libp2p-dns = { version = "0.36.0", path = "transports/dns", optional = true, def
libp2p-mdns = { version = "0.40.0", path = "protocols/mdns", optional = true, default-features = false }
libp2p-tcp = { version = "0.37.0", path = "transports/tcp", default-features = false, optional = true }
libp2p-websocket = { version = "0.38.0", path = "transports/websocket", optional = true }
libp2p-onion = { version = "0.1.0", path = "transports/onion", default-features = false, optional = true }

[target.'cfg(not(target_os = "unknown"))'.dependencies]
libp2p-gossipsub = { version = "0.41.0", path = "protocols/gossipsub", optional = true }
Expand Down Expand Up @@ -154,7 +163,8 @@ members = [
"transports/tcp",
"transports/uds",
"transports/websocket",
"transports/wasm-ext"
"transports/wasm-ext",
"transports/onion"
]

[[example]]
Expand All @@ -176,3 +186,7 @@ required-features = ["gossipsub"]
[[example]]
name = "ipfs-private"
required-features = ["gossipsub"]

[[example]]
name = "ping-onion"
required-features = ["onion", "onion-async-std", "onion-native-tls", "tcp-async-io", "dns-async-std"]
122 changes: 122 additions & 0 deletions examples/ping-onion.rs
@@ -0,0 +1,122 @@
// Copyright 2018 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved

//! Ping example
//!
//! See ../src/tutorial.rs for a step-by-step guide building the example below.
//!
//! In the first terminal window, run:
//!
//! ```sh
//! cargo run --example ping-onion
//! ```
//!
//! It will print the PeerId and the listening addresses, e.g. `Listening on
//! "/ip4/0.0.0.0/tcp/24915"`
//!
//! In the second terminal window, start a new instance of the example with:
//!
//! ```sh
//! cargo run --example ping-onion -- /ip4/127.0.0.1/tcp/24915
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
//! ```
//!
//! The two nodes establish a connection, negotiate the ping protocol
//! and begin pinging each other.
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved

use futures::prelude::*;
use libp2p::swarm::{Swarm, SwarmEvent};
use libp2p::{
core::upgrade, dns, identity, mplex, noise, onion, ping, tcp, yamux, Multiaddr, PeerId,
Transport,
};
use std::error::Error;

async fn onion_transport(
keypair: identity::Keypair,
) -> Result<
libp2p_core::transport::Boxed<(PeerId, libp2p_core::muxing::StreamMuxerBox)>,
Box<dyn Error>,
> {
use std::time::Duration;

let transport = {
let dns_tcp = dns::DnsConfig::system(tcp::TcpTransport::new(
tcp::GenTcpConfig::new().nodelay(true),
))
.await?;
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
let onion = onion::OnionClient::from_builder(onion::OnionClient::builder(), false)?;
println!("bootstrapping...");
onion.bootstrap().await?;
println!("bootstrapped!");
onion.or_transport(dns_tcp)
};

let noise_keys = noise::Keypair::<noise::X25519Spec>::new()
.into_authentic(&keypair)
.expect("Signing libp2p-noise static DH keypair failed.");
Ok(transport
.upgrade(upgrade::Version::V1)
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
.multiplex(upgrade::SelectUpgrade::new(
yamux::YamuxConfig::default(),
mplex::MplexConfig::default(),
))
.timeout(Duration::from_secs(20))
.boxed())
}

#[async_std::main]
async fn main() -> Result<(), Box<dyn Error>> {
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
println!("Local peer id: {:?}", local_peer_id);

// create a transport
let transport = onion_transport(local_key).await?;

// Create a ping network behaviour.
//
// For illustrative purposes, the ping protocol is configured to
// keep the connection alive, so a continuous sequence of pings
// can be observed.
let behaviour = ping::Behaviour::new(ping::Config::new().with_keep_alive(true));

let mut swarm = Swarm::new(transport, behaviour, local_peer_id);

// Tell the swarm to listen on all interfaces and a random, OS-assigned
// port.
swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
umgefahren marked this conversation as resolved.
Show resolved Hide resolved

// Dial the peer identified by the multi-address given as the second
// command-line argument, if any.
if let Some(addr) = std::env::args().nth(1) {
let remote: Multiaddr = addr.parse()?;
swarm.dial(remote)?;
println!("Dialed {}", addr)
}

loop {
match swarm.select_next_some().await {
SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {:?}", address),
SwarmEvent::Behaviour(event) => println!("{:?}", event),
_ => {}
}
}
}
4 changes: 4 additions & 0 deletions src/lib.rs
Expand Up @@ -99,6 +99,10 @@ pub use libp2p_mplex as mplex;
#[cfg_attr(docsrs, doc(cfg(feature = "noise")))]
#[doc(inline)]
pub use libp2p_noise as noise;
#[cfg(feature = "onion")]
#[cfg_attr(docsrs, doc(cfg(feature = "onion")))]
#[doc(inline)]
pub use libp2p_onion as onion;
#[cfg(feature = "ping")]
#[cfg_attr(docsrs, doc(cfg(feature = "ping")))]
#[doc(inline)]
Expand Down
33 changes: 33 additions & 0 deletions transports/onion/Cargo.toml
@@ -0,0 +1,33 @@
[package]
name = "libp2p-onion"
version = "0.1.0"
umgefahren marked this conversation as resolved.
Show resolved Hide resolved
edition = "2021"
license = "MIT"
resolver = "2"


thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
[dependencies]
libp2p-core = { version = "0.36.0", path = "../../core", default-features = false }
futures = "0.3"
arti-client = { version = "0.6", default-features = false }
thiserror = "1"
tor-rtcompat = "0.6"
tokio-crate = { package = "tokio", version = "1", optional = true, default-features = false }
async-std-crate = { package = "async-std", version = "1", optional = true, default-features = false }

[dev-dependencies]
libp2p = { version = "0.49", path = "../../" }
tokio-crate = { package = "tokio", version = "1", features = ["rt", "macros"] }
async-std-crate = { package = "async-std", version = "1", features = ["attributes"] }


[features]
default = ["async-std", "native-tls"]
tokio = ["arti-client/tokio", "dep:tokio-crate"]
async-std = ["arti-client/async-std"]
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
native-tls = ["arti-client/native-tls"]
rustls = ["arti-client/rustls"]

[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
rustc-args = ["--cfg", "docsrs"]
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
80 changes: 80 additions & 0 deletions transports/onion/src/address.rs
@@ -0,0 +1,80 @@
use std::net::{IpAddr, SocketAddr};

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

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 multiaddr.iter() {
match e {
Protocol::Ip4(a) => {
ip_4 = Some(IpAddr::V4(a));
}
Protocol::Ip6(a) => {
ip_6 = Some(IpAddr::V6(a));
}
Protocol::Tcp(p) => {
tcp_port_opt = Some(p);
}
_ => {}
}
}
let ip = ip_4.or(ip_6).ok_or(TorAddrError::InvalidHostname)?;
let tcp_port = tcp_port_opt.ok_or(TorAddrError::NoPort)?;
Ok(SocketAddr::new(ip, tcp_port))
}

pub(super) fn dangerous_extract_tor_address(
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
multiaddr: &Multiaddr,
) -> Result<TorAddr, TorAddrError> {
let socket_addr = try_extract_socket_addr(multiaddr)?;
TorAddr::dangerously_from(socket_addr)
}
umgefahren marked this conversation as resolved.
Show resolved Hide resolved

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))
}