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

Shift dual stack support to use two sockets instead of mapped addresses #160

Merged
merged 57 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
6edda35
progress dealing with a second recv socket
divagant-martian Feb 19, 2023
b0c2f7c
wip
divagant-martian Feb 19, 2023
41be7e7
remove unused file
divagant-martian Feb 19, 2023
d891e85
start changes to two send sockets
divagant-martian Feb 22, 2023
cb42618
wip
divagant-martian Feb 23, 2023
b7ded33
Make build pass
ackintosh Mar 11, 2023
528a98c
Make Discv5::new requires ListenConfig and update `find_node` example
ackintosh Mar 11, 2023
7d3b281
Remove useless comments
ackintosh Mar 11, 2023
e087d6a
Remove unnecessary qualification
ackintosh Mar 11, 2023
f63ac1d
Make tests pass
ackintosh Mar 15, 2023
845b532
Make SendHandler uses two sockets
ackintosh Mar 15, 2023
d149eb2
listen_socket holds two sockets
ackintosh Mar 17, 2023
8635832
Add a test for the case of self-request
ackintosh Mar 18, 2023
9c3454a
Add tests for running a simple query test
ackintosh Mar 18, 2023
1d41759
Add tests for non-contactable nodes
ackintosh Mar 18, 2023
54002f2
Tweak listen_sockets
ackintosh Mar 19, 2023
ae6eb4f
Checking if loopback address
ackintosh Mar 19, 2023
03f46c8
No longer need to treat mapped address
ackintosh Mar 20, 2023
7d92d2e
cargo fmt
ackintosh Mar 21, 2023
aa00309
Fix doc
ackintosh Mar 21, 2023
85fe2ed
Update README
ackintosh Mar 21, 2023
5cd9409
Tweak ports to avoid `Address already in use`
ackintosh Mar 21, 2023
e418016
Merge pull request #1 from ackintosh/two-sockets-ackintosh
divagant-martian Mar 28, 2023
770a7dd
Merge branch 'master' into two-sockets
divagant-martian Apr 5, 2023
a82906d
clippy
divagant-martian Apr 5, 2023
9d75e47
fmt
divagant-martian Apr 5, 2023
31c1b9a
get tests working without ipv6 - kinda
divagant-martian Apr 5, 2023
81b7a3b
Revert "get tests working without ipv6 - kinda"
ackintosh Apr 13, 2023
eca11dc
Skip some tests if IPv6 is not supported
ackintosh Apr 13, 2023
d5fbb1c
Separate `test_self_request` into ipv4 and ipv6.
ackintosh Apr 13, 2023
2679758
Add a comment
ackintosh Apr 13, 2023
0311430
Merge pull request #2 from ackintosh/two-sockets-tests
divagant-martian Apr 14, 2023
1ee56ef
Add `listen_config` to Discv5ConfigBuilder
ackintosh Apr 15, 2023
108c2dc
Remove `listen_config` from Discv5
ackintosh Apr 15, 2023
f735c33
Fix tests and examples
ackintosh Apr 15, 2023
356603e
Fix doc
ackintosh Apr 15, 2023
82de33b
cargo fmt
ackintosh Apr 15, 2023
3bed74c
Fix example
ackintosh Apr 15, 2023
b716845
cargo fmt
ackintosh Apr 15, 2023
c431035
Merge pull request #3 from ackintosh/two-sockets-listen-config
divagant-martian Apr 15, 2023
9e79fbe
Merge branch 'master' into two-sockets
divagant-martian May 4, 2023
1bff255
fixes
divagant-martian May 4, 2023
2a8a195
Merge branch 'master' into two-sockets
divagant-martian May 4, 2023
2d7bbfd
update readme
divagant-martian May 4, 2023
e3dea6a
update readme
divagant-martian May 4, 2023
86e6233
revert query interval to match comments
divagant-martian May 5, 2023
ab93874
Zero out ipv6 extra fields
divagant-martian May 15, 2023
e58ed88
fix unused import warns
divagant-martian May 15, 2023
ae0d73c
better error handling in send addressing comments from @AgeManning
divagant-martian May 15, 2023
2a70c27
improve ergonomics for ListenConfig. Not super sure about this one
divagant-martian May 15, 2023
4ec1a6d
Merge branch 'master' into two-sockets
divagant-martian May 15, 2023
5ad5ba0
give direct access to the ListenConfig
divagant-martian May 15, 2023
a7defe8
remove duplicated word in omment
divagant-martian May 16, 2023
b44b28c
Document `ListenConfig` functions
divagant-martian May 16, 2023
b651fb3
Improve docs for `ListenConfig` functions
divagant-martian May 16, 2023
b98bf6e
Document `ListenConfig` functions
divagant-martian May 16, 2023
4af25a3
Document `ListenConfig` functions
divagant-martian May 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ tokio = { version = "1.15.0", features = ["full"] }
rand_xorshift = "0.3.0"
rand_core = "0.6.3"
clap = { version = "3.1", features = ["derive"] }
if-addrs = "0.10.1"

[features]
libp2p = ["libp2p-core"]
Expand Down
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@ A simple example of creating this service is as follows:

```rust
use discv5::{enr, enr::{CombinedKey, NodeId}, TokioExecutor, Discv5, Discv5ConfigBuilder};
use discv5::socket::ListenConfig;
use std::net::SocketAddr;

// listening address and port
let listen_addr = "0.0.0.0:9000".parse::<SocketAddr>().unwrap();

// construct a local ENR
let enr_key = CombinedKey::generate_secp256k1();
let enr = enr::EnrBuilder::new("v4").build(&enr_key).unwrap();
Expand All @@ -54,8 +52,14 @@ A simple example of creating this service is as follows:
.build()
.unwrap();

// configuration for the sockets to listen on
let listen_config = ListenConfig::Ipv4 {
ip: Ipv4Addr::UNSPECIFIED,
port: 9000,
};

// default configuration
let config = Discv5ConfigBuilder::new().build();
let config = Discv5ConfigBuilder::new(listen_config).build();

// construct the discv5 server
let mut discv5: Discv5 = Discv5::new(enr, enr_key, config).unwrap();
Expand All @@ -65,7 +69,7 @@ A simple example of creating this service is as follows:
// discv5.add_enr(<ENR>)

// start the discv5 server
runtime.block_on(discv5.start(listen_addr));
runtime.block_on(discv5.start());

// run a find_node query
runtime.block_on(async {
Expand Down
15 changes: 10 additions & 5 deletions examples/custom_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
//! $ cargo run --example custom_executor <BASE64ENR>
//! ```

use discv5::{enr, enr::CombinedKey, Discv5, Discv5ConfigBuilder, Discv5Event};
use std::net::SocketAddr;
use discv5::{
enr, enr::CombinedKey, socket::ListenConfig, Discv5, Discv5ConfigBuilder, Discv5Event,
};
use std::net::Ipv4Addr;

fn main() {
// allows detailed logging with the RUST_LOG env variable
Expand All @@ -22,7 +24,10 @@ fn main() {
.try_init();

// listening address and port
let listen_addr = "0.0.0.0:9000".parse::<SocketAddr>().unwrap();
let listen_config = ListenConfig::Ipv4 {
ip: Ipv4Addr::UNSPECIFIED,
port: 9000,
};

let enr_key = CombinedKey::generate_secp256k1();
// construct a local ENR
Expand All @@ -36,7 +41,7 @@ fn main() {
.unwrap();

// default configuration - uses the current executor
let config = Discv5ConfigBuilder::new().build();
let config = Discv5ConfigBuilder::new(listen_config).build();

// construct the discv5 server
let mut discv5: Discv5 = Discv5::new(enr, enr_key, config).unwrap();
Expand All @@ -61,7 +66,7 @@ fn main() {

runtime.block_on(async {
// start the discv5 service
discv5.start(listen_addr).await.unwrap();
discv5.start().await.unwrap();
println!("Server started");

// get an event stream
Expand Down
60 changes: 36 additions & 24 deletions examples/find_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ use clap::Parser;
use discv5::{
enr,
enr::{k256, CombinedKey},
socket::ListenConfig,
Discv5, Discv5ConfigBuilder, Discv5Event,
};
use std::{
net::{Ipv4Addr, Ipv6Addr, SocketAddr},
net::{Ipv4Addr, Ipv6Addr},
time::Duration,
};
use tracing::{info, warn};

#[derive(Parser)]
struct FindNodesArgs {
/// Type of socket to bind ['ds', 'ip4', 'ip6']. The dual stack option will enable mapped
/// addresses over an IpV6 socket.
/// Type of socket to bind ['ds', 'ip4', 'ip6'].
#[clap(long, default_value_t = SocketKind::Ds)]
socket_kind: SocketKind,
/// IpV4 to advertise in the ENR. This is needed so that other IpV4 nodes can connect to us.
Expand All @@ -43,6 +43,10 @@ struct FindNodesArgs {
/// randomly.
#[clap(long)]
port: Option<u16>,
/// Port to bind for ipv6. If none is provided, a random one in the 9000 - 9999 range will be picked
/// randomly.
#[clap(long)]
port6: Option<u16>,
/// Use a default test key.
#[clap(long)]
use_test_key: bool,
Expand All @@ -67,6 +71,12 @@ async fn main() {
let port = args
.port
.unwrap_or_else(|| (rand::random::<u16>() % 1000) + 9000);
let port6 = args.port.unwrap_or_else(|| loop {
let port6 = (rand::random::<u16>() % 1000) + 9000;
if port6 != port {
return port6;
}
});

let enr_key = if args.use_test_key {
// A fixed key for testing
Expand All @@ -93,29 +103,37 @@ async fn main() {
if let Some(ip6) = args.enr_ip6 {
// if the given address is the UNSPECIFIED address we want to advertise localhost
if ip6.is_unspecified() {
builder.ip6(Ipv6Addr::LOCALHOST).udp6(port);
builder.ip6(Ipv6Addr::LOCALHOST).udp6(port6);
} else {
builder.ip6(ip6).udp6(port);
builder.ip6(ip6).udp6(port6);
}
}
builder.build(&enr_key).unwrap()
};

// the address to listen on.
let listen_config = match args.socket_kind {
SocketKind::Ip4 => ListenConfig::Ipv4 {
ip: Ipv4Addr::UNSPECIFIED,
port,
},
SocketKind::Ip6 => ListenConfig::Ipv6 {
ip: Ipv6Addr::UNSPECIFIED,
port: port6,
},
SocketKind::Ds => ListenConfig::DualStack {
ipv4: Ipv4Addr::UNSPECIFIED,
ipv4_port: port,
ipv6: Ipv6Addr::UNSPECIFIED,
ipv6_port: port6,
},
};

// default configuration with packet filtering
// let config = Discv5ConfigBuilder::new().enable_packet_filter().build();
// let config = Discv5ConfigBuilder::new(listen_config).enable_packet_filter().build();

// default configuration without packet filtering
let config = Discv5ConfigBuilder::new()
.ip_mode(match args.socket_kind {
SocketKind::Ip4 => discv5::IpMode::Ip4,
SocketKind::Ip6 => discv5::IpMode::Ip6 {
enable_mapped_addresses: false,
},
SocketKind::Ds => discv5::IpMode::Ip6 {
enable_mapped_addresses: true,
},
})
.build();
let config = Discv5ConfigBuilder::new(listen_config).build();

info!("Node Id: {}", enr.node_id());
if args.enr_ip6.is_some() || args.enr_ip4.is_some() {
Expand All @@ -127,12 +145,6 @@ async fn main() {
enr.udp4_socket()
);
}
// the address to listen on.
let bind_addr = match args.socket_kind {
SocketKind::Ip4 => Ipv4Addr::UNSPECIFIED.into(),
SocketKind::Ip6 | SocketKind::Ds => Ipv6Addr::UNSPECIFIED.into(),
};
let socket_addr = SocketAddr::new(bind_addr, port);

// construct the discv5 server
let mut discv5: Discv5 = Discv5::new(enr, enr_key, config).unwrap();
Expand All @@ -154,7 +166,7 @@ async fn main() {
}

// start the discv5 service
discv5.start(socket_addr).await.unwrap();
discv5.start().await.unwrap();
let mut event_stream = discv5.event_stream().await.unwrap();
let check_evs = args.events;

Expand Down
15 changes: 10 additions & 5 deletions examples/request_enr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
//!
//! This requires the "libp2p" feature.
#[cfg(feature = "libp2p")]
use discv5::{enr, enr::CombinedKey, Discv5, Discv5Config};
use discv5::socket::ListenConfig;
use discv5::Discv5ConfigBuilder;
#[cfg(feature = "libp2p")]
use std::net::SocketAddr;
use discv5::{enr, enr::CombinedKey, Discv5, Discv5Config};
use std::net::Ipv4Addr;

#[cfg(not(feature = "libp2p"))]
fn main() {}
Expand All @@ -31,15 +33,18 @@ async fn main() {
.try_init();

// listening address and port
let listen_addr = "0.0.0.0:9000".parse::<SocketAddr>().unwrap();
let listen_config = ListenConfig::Ipv4 {
ip: Ipv4Addr::UNSPECIFIED,
port: 9000,
};

// generate a new enr key
let enr_key = CombinedKey::generate_secp256k1();
// construct a local ENR
let enr = enr::EnrBuilder::new("v4").build(&enr_key).unwrap();

// default discv5 configuration
let config = Discv5Config::default();
let config = Discv5ConfigBuilder::new(listen_config).build();

let multiaddr = std::env::args()
.nth(1)
Expand All @@ -49,7 +54,7 @@ async fn main() {
let mut discv5: Discv5 = Discv5::new(enr, enr_key, config).unwrap();

// start the discv5 service
discv5.start(listen_addr).await.unwrap();
discv5.start().await.unwrap();

// search for the ENR
match discv5.request_enr(multiaddr).await {
Expand Down
15 changes: 10 additions & 5 deletions examples/simple_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
//! $ cargo run --example simple_server -- <ENR-IP> <ENR-PORT> <BASE64ENR>
//! ```

use discv5::{enr, enr::CombinedKey, Discv5, Discv5Config, Discv5Event};
use std::net::{Ipv4Addr, SocketAddr};
use discv5::{
enr, enr::CombinedKey, socket::ListenConfig, Discv5, Discv5ConfigBuilder, Discv5Event,
};
use std::net::Ipv4Addr;

#[tokio::main]
async fn main() {
Expand All @@ -37,7 +39,10 @@ async fn main() {
};

// listening address and port
let listen_addr = "0.0.0.0:9000".parse::<SocketAddr>().unwrap();
let listen_config = ListenConfig::Ipv4 {
ip: Ipv4Addr::UNSPECIFIED,
port: 9000,
};

let enr_key = CombinedKey::generate_secp256k1();

Expand Down Expand Up @@ -69,7 +74,7 @@ async fn main() {
}

// default configuration
let config = Discv5Config::default();
let config = Discv5ConfigBuilder::new(listen_config).build();

// construct the discv5 server
let mut discv5: Discv5 = Discv5::new(enr, enr_key, config).unwrap();
Expand All @@ -93,7 +98,7 @@ async fn main() {
}

// start the discv5 service
discv5.start(listen_addr).await.unwrap();
discv5.start().await.unwrap();
println!("Server started");

// get an event stream
Expand Down
45 changes: 17 additions & 28 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
ipmode::IpMode, kbucket::MAX_NODES_PER_BUCKET, Enr, Executor, PermitBanList, RateLimiter,
kbucket::MAX_NODES_PER_BUCKET, socket::ListenConfig, Enr, Executor, PermitBanList, RateLimiter,
RateLimiterBuilder,
};
///! A set of configuration parameters to tune the discovery protocol.
Expand Down Expand Up @@ -64,10 +64,6 @@ pub struct Discv5Config {
/// seconds.
pub ping_interval: Duration,

/// Configures the type of socket to bind to. This also affects the selection of address to use
/// to contact an ENR.
pub ip_mode: IpMode,

/// Reports all discovered ENR's when traversing the DHT to the event stream. Default true.
pub report_discovered_peers: bool,

Expand Down Expand Up @@ -99,10 +95,18 @@ pub struct Discv5Config {
/// A custom executor which can spawn the discv5 tasks. This must be a tokio runtime, with
/// timing support. By default, the executor that created the discv5 struct will be used.
pub executor: Option<Box<dyn Executor + Send + Sync>>,

/// Configuration for the sockets to listen on.
pub listen_config: ListenConfig,
}

#[derive(Debug)]
pub struct Discv5ConfigBuilder {
config: Discv5Config,
}

impl Default for Discv5Config {
fn default() -> Self {
impl Discv5ConfigBuilder {
pub fn new(listen_config: ListenConfig) -> Self {
// This is only applicable if enable_packet_filter is set.
let filter_rate_limiter = Some(
RateLimiterBuilder::new()
Expand All @@ -113,7 +117,8 @@ impl Default for Discv5Config {
.expect("The total rate limit has been specified"),
);

Self {
// set default values
let config = Discv5Config {
enable_packet_filter: false,
request_timeout: Duration::from_secs(1),
vote_duration: Duration::from_secs(30),
Expand All @@ -136,21 +141,11 @@ impl Default for Discv5Config {
filter_max_bans_per_ip: Some(5),
permit_ban_list: PermitBanList::default(),
ban_duration: Some(Duration::from_secs(3600)), // 1 hour
ip_mode: IpMode::default(),
executor: None,
}
}
}

#[derive(Debug, Default)]
pub struct Discv5ConfigBuilder {
config: Discv5Config,
}
listen_config,
};

impl Discv5ConfigBuilder {
// set default values
pub fn new() -> Self {
Discv5ConfigBuilder::default()
Discv5ConfigBuilder { config }
}

/// Whether to enable the incoming packet filter.
Expand Down Expand Up @@ -307,13 +302,6 @@ impl Discv5ConfigBuilder {
self
}

/// Configures the type of socket to bind to. This also affects the selection of address to use
/// to contact an ENR.
pub fn ip_mode(&mut self, ip_mode: IpMode) -> &mut Self {
self.config.ip_mode = ip_mode;
self
}

pub fn build(&mut self) -> Discv5Config {
// If an executor is not provided, assume a current tokio runtime is running.
if self.config.executor.is_none() {
Expand Down Expand Up @@ -347,6 +335,7 @@ impl std::fmt::Debug for Discv5Config {
.field("incoming_bucket_limit", &self.incoming_bucket_limit)
.field("ping_interval", &self.ping_interval)
.field("ban_duration", &self.ban_duration)
.field("listen_config", &self.listen_config)
.finish()
}
}
Loading