forked from libp2p/rust-libp2p
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes: libp2p#4524 This is the implementation of the evolved AutoNAT protocol, named AutonatV2 as defined in the [spec](https://github.com/libp2p/specs/blob/03718ef0f2dea4a756a85ba716ee33f97e4a6d6c/autonat/autonat-v2.md). The stabilization PR for the spec can be found under libp2p/specs#538. The work on the Rust implementation can be found in the PR to my fork: #1. The implementation has been smoke-tested with the Go implementation (PR: libp2p/go-libp2p#2469). The new protocol addresses shortcomings of the original AutoNAT protocol: - Since the server now always dials back over a newly allocated port, this made libp2p#4568 necessary; the client can be sure of the reachability state for other peers, even if the connection to the server was made through a hole punch. - The server can now test addresses different from the observed address (i.e., the connection to the server was made through a `p2p-circuit`). To mitigate against DDoS attacks, the client has to send more data to the server than the dial-back costs. Pull-Request: libp2p#5526.
- Loading branch information
1 parent
ddda3be
commit 848e2e9
Showing
34 changed files
with
3,525 additions
and
80 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
[package] | ||
name = "autonatv2" | ||
version = "0.1.0" | ||
edition = "2021" | ||
publish = false | ||
license = "MIT or Apache-2.0" | ||
|
||
[package.metadata.release] | ||
release = false | ||
|
||
[[bin]] | ||
name = "autonatv2_client" | ||
|
||
[[bin]] | ||
name = "autonatv2_server" | ||
|
||
[dependencies] | ||
libp2p = { workspace = true, features = ["macros", "tokio", "tcp", "noise", "yamux", "autonat", "identify", "dns", "quic"] } | ||
clap = { version = "4.4.18", features = ["derive"] } | ||
tokio = { version = "1.35.1", features = ["macros", "rt-multi-thread"] } | ||
tracing = "0.1.40" | ||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } | ||
rand = "0.8.5" | ||
opentelemetry = { version = "0.21.0", optional = true } | ||
opentelemetry_sdk = { version = "0.21.1", optional = true, features = ["rt-tokio"] } | ||
tracing-opentelemetry = { version = "0.22.0", optional = true } | ||
opentelemetry-jaeger = { version = "0.20.0", optional = true, features = ["rt-tokio"] } | ||
cfg-if = "1.0.0" | ||
|
||
[features] | ||
jaeger = ["opentelemetry", "opentelemetry_sdk", "tracing-opentelemetry", "opentelemetry-jaeger"] | ||
opentelemetry = ["dep:opentelemetry"] | ||
opentelemetry_sdk = ["dep:opentelemetry_sdk"] | ||
tracing-opentelemetry = ["dep:tracing-opentelemetry"] | ||
opentelemetry-jaeger = ["dep:opentelemetry-jaeger"] | ||
|
||
[lints] | ||
workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
FROM rust:1.75-alpine as builder | ||
|
||
RUN apk add musl-dev | ||
|
||
WORKDIR /workspace | ||
COPY . . | ||
RUN --mount=type=cache,target=./target \ | ||
--mount=type=cache,target=/usr/local/cargo/registry \ | ||
cargo build --release --package autonatv2 --bin autonatv2_server -F jaeger | ||
|
||
RUN --mount=type=cache,target=./target \ | ||
mv ./target/release/autonatv2_server /usr/local/bin/autonatv2_server | ||
|
||
FROM alpine:latest | ||
|
||
COPY --from=builder /usr/local/bin/autonatv2_server /app/autonatv2_server | ||
|
||
EXPOSE 4884 | ||
|
||
ENTRYPOINT [ "/app/autonatv2_server", "-l", "4884" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
version: '3' | ||
|
||
services: | ||
autonatv2: | ||
build: | ||
context: ../.. | ||
dockerfile: examples/autonatv2/Dockerfile | ||
ports: | ||
- 4884:4884 | ||
jaeger: | ||
image: jaegertracing/all-in-one | ||
ports: | ||
- 6831:6831/udp | ||
- 6832:6832/udp | ||
- 16686:16686 | ||
- 14268:14268 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
use std::{error::Error, net::Ipv4Addr, time::Duration}; | ||
|
||
use clap::Parser; | ||
use libp2p::{ | ||
autonat, | ||
futures::StreamExt, | ||
identify, identity, | ||
multiaddr::Protocol, | ||
noise, | ||
swarm::{dial_opts::DialOpts, NetworkBehaviour, SwarmEvent}, | ||
tcp, yamux, Multiaddr, SwarmBuilder, | ||
}; | ||
use rand::rngs::OsRng; | ||
use tracing_subscriber::EnvFilter; | ||
|
||
#[derive(Debug, Parser)] | ||
#[clap(name = "libp2p autonatv2 client")] | ||
struct Opt { | ||
/// Port where the client will listen for incoming connections. | ||
#[clap(short = 'p', long, default_value_t = 0)] | ||
listen_port: u16, | ||
|
||
/// Address of the server where want to connect to. | ||
#[clap(short = 'a', long)] | ||
server_address: Multiaddr, | ||
|
||
/// Probe interval in seconds. | ||
#[clap(short = 't', long, default_value = "2")] | ||
probe_interval: u64, | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn Error>> { | ||
let _ = tracing_subscriber::fmt() | ||
.with_env_filter(EnvFilter::from_default_env()) | ||
.try_init(); | ||
|
||
let opt = Opt::parse(); | ||
|
||
let mut swarm = SwarmBuilder::with_new_identity() | ||
.with_tokio() | ||
.with_tcp( | ||
tcp::Config::default(), | ||
noise::Config::new, | ||
yamux::Config::default, | ||
)? | ||
.with_quic() | ||
.with_dns()? | ||
.with_behaviour(|key| Behaviour::new(key.public(), opt.probe_interval))? | ||
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(10))) | ||
.build(); | ||
|
||
swarm.listen_on( | ||
Multiaddr::empty() | ||
.with(Protocol::Ip4(Ipv4Addr::UNSPECIFIED)) | ||
.with(Protocol::Tcp(opt.listen_port)), | ||
)?; | ||
|
||
swarm.dial( | ||
DialOpts::unknown_peer_id() | ||
.address(opt.server_address) | ||
.build(), | ||
)?; | ||
|
||
loop { | ||
match swarm.select_next_some().await { | ||
SwarmEvent::NewListenAddr { address, .. } => { | ||
println!("Listening on {address:?}"); | ||
} | ||
SwarmEvent::Behaviour(BehaviourEvent::Autonat(autonat::v2::client::Event { | ||
server, | ||
tested_addr, | ||
bytes_sent, | ||
result: Ok(()), | ||
})) => { | ||
println!("Tested {tested_addr} with {server}. Sent {bytes_sent} bytes for verification. Everything Ok and verified."); | ||
} | ||
SwarmEvent::Behaviour(BehaviourEvent::Autonat(autonat::v2::client::Event { | ||
server, | ||
tested_addr, | ||
bytes_sent, | ||
result: Err(e), | ||
})) => { | ||
println!("Tested {tested_addr} with {server}. Sent {bytes_sent} bytes for verification. Failed with {e:?}."); | ||
} | ||
SwarmEvent::ExternalAddrConfirmed { address } => { | ||
println!("External address confirmed: {address}"); | ||
} | ||
_ => {} | ||
} | ||
} | ||
} | ||
|
||
#[derive(NetworkBehaviour)] | ||
pub struct Behaviour { | ||
autonat: autonat::v2::client::Behaviour, | ||
identify: identify::Behaviour, | ||
} | ||
|
||
impl Behaviour { | ||
pub fn new(key: identity::PublicKey, probe_interval: u64) -> Self { | ||
Self { | ||
autonat: autonat::v2::client::Behaviour::new( | ||
OsRng, | ||
autonat::v2::client::Config::default() | ||
.with_probe_interval(Duration::from_secs(probe_interval)), | ||
), | ||
identify: identify::Behaviour::new(identify::Config::new("/ipfs/0.1.0".into(), key)), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
use std::{error::Error, net::Ipv4Addr, time::Duration}; | ||
|
||
use cfg_if::cfg_if; | ||
use clap::Parser; | ||
use libp2p::{ | ||
autonat, | ||
futures::StreamExt, | ||
identify, identity, | ||
multiaddr::Protocol, | ||
noise, | ||
swarm::{NetworkBehaviour, SwarmEvent}, | ||
tcp, yamux, Multiaddr, SwarmBuilder, | ||
}; | ||
use rand::rngs::OsRng; | ||
|
||
#[derive(Debug, Parser)] | ||
#[clap(name = "libp2p autonatv2 server")] | ||
struct Opt { | ||
#[clap(short, long, default_value_t = 0)] | ||
listen_port: u16, | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn Error>> { | ||
cfg_if! { | ||
if #[cfg(feature = "jaeger")] { | ||
use tracing_subscriber::layer::SubscriberExt; | ||
use opentelemetry_sdk::runtime::Tokio; | ||
let tracer = opentelemetry_jaeger::new_agent_pipeline() | ||
.with_endpoint("jaeger:6831") | ||
.with_service_name("autonatv2") | ||
.install_batch(Tokio)?; | ||
let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); | ||
let subscriber = tracing_subscriber::Registry::default() | ||
.with(telemetry); | ||
} else { | ||
let subscriber = tracing_subscriber::fmt() | ||
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) | ||
.finish(); | ||
} | ||
} | ||
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); | ||
|
||
let opt = Opt::parse(); | ||
|
||
let mut swarm = SwarmBuilder::with_new_identity() | ||
.with_tokio() | ||
.with_tcp( | ||
tcp::Config::default(), | ||
noise::Config::new, | ||
yamux::Config::default, | ||
)? | ||
.with_quic() | ||
.with_dns()? | ||
.with_behaviour(|key| Behaviour::new(key.public()))? | ||
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) | ||
.build(); | ||
|
||
swarm.listen_on( | ||
Multiaddr::empty() | ||
.with(Protocol::Ip4(Ipv4Addr::UNSPECIFIED)) | ||
.with(Protocol::Tcp(opt.listen_port)), | ||
)?; | ||
|
||
loop { | ||
match swarm.select_next_some().await { | ||
SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {address:?}"), | ||
SwarmEvent::Behaviour(event) => println!("{event:?}"), | ||
e => println!("{e:?}"), | ||
} | ||
} | ||
} | ||
|
||
#[derive(NetworkBehaviour)] | ||
pub struct Behaviour { | ||
autonat: autonat::v2::server::Behaviour, | ||
identify: identify::Behaviour, | ||
} | ||
|
||
impl Behaviour { | ||
pub fn new(key: identity::PublicKey) -> Self { | ||
Self { | ||
autonat: autonat::v2::server::Behaviour::new(OsRng), | ||
identify: identify::Behaviour::new(identify::Config::new("/ipfs/0.1.0".into(), key)), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,32 +3,47 @@ name = "libp2p-autonat" | |
edition = "2021" | ||
rust-version = { workspace = true } | ||
description = "NAT and firewall detection for libp2p" | ||
authors = ["David Craven <[email protected]>", "Elena Frank <[email protected]>"] | ||
version = "0.13.0" | ||
authors = ["David Craven <[email protected]>", "Elena Frank <[email protected]>", "Hannes Furmans <[email protected]>"] | ||
license = "MIT" | ||
repository = "https://github.com/libp2p/rust-libp2p" | ||
keywords = ["peer-to-peer", "libp2p", "networking"] | ||
categories = ["network-programming", "asynchronous"] | ||
|
||
|
||
[dependencies] | ||
async-trait = "0.1" | ||
async-trait = { version = "0.1", optional = true } | ||
asynchronous-codec = { workspace = true } | ||
bytes = { version = "1", optional = true } | ||
either = { version = "1.9.0", optional = true } | ||
futures = { workspace = true } | ||
futures-bounded = { workspace = true, optional = true } | ||
futures-timer = "3.0" | ||
web-time = { workspace = true } | ||
web-time = { workspace = true, optional = true } | ||
libp2p-core = { workspace = true } | ||
libp2p-swarm = { workspace = true } | ||
libp2p-request-response = { workspace = true } | ||
libp2p-identity = { workspace = true } | ||
libp2p-request-response = { workspace = true, optional = true } | ||
libp2p-swarm = { workspace = true } | ||
quick-protobuf = "0.8" | ||
rand = "0.8" | ||
tracing = { workspace = true } | ||
quick-protobuf-codec = { workspace = true } | ||
asynchronous-codec = { workspace = true } | ||
rand = "0.8" | ||
rand_core = { version = "0.6", optional = true } | ||
thiserror = { version = "1.0.52", optional = true } | ||
void = { version = "1", optional = true } | ||
|
||
[dev-dependencies] | ||
tokio = { version = "1", features = ["macros", "rt", "sync"]} | ||
async-std = { version = "1.10", features = ["attributes"] } | ||
libp2p-swarm-test = { path = "../../swarm-test" } | ||
tracing-subscriber = { workspace = true, features = ["env-filter"] } | ||
tracing-subscriber = { version = "0.3", features = ["env-filter"] } | ||
libp2p-identify = { workspace = true } | ||
libp2p-swarm = { workspace = true, features = ["macros"]} | ||
|
||
[features] | ||
default = ["v1", "v2"] | ||
v1 = ["dep:libp2p-request-response", "dep:web-time", "dep:async-trait"] | ||
v2 = ["dep:bytes", "dep:either", "dep:futures-bounded", "dep:thiserror", "dep:void", "dep:rand_core"] | ||
|
||
# Passing arguments to the docsrs builder in order to properly document cfg's. | ||
# More information: https://docs.rs/about/builds#cross-compiling | ||
|
Oops, something went wrong.