Skip to content

Commit 04f2dc6

Browse files
emhaneEmilia Hanemichaelsprouldivagant-martianAgeManning
authored
Nat hole punching for discv5.2 (#176)
* Plug-in hole punching * Notification message container * Plug relaying into service * Move hole punch trait to extern crate * Adjust impl of hole punch trait * fixup! Plug relaying into service * fixup! Plug-in hole punching * Update trait impl * Consolidate hole punching in Handler * fixup! Consolidate hole punching in Handler * fixup! Consolidate hole punching in Handler * Add trace info * fixup! Consolidate hole punching in Handler * Reinsert active request on hole punch attempt * Update node address conversion * RO access kbuckets from handler for hole punch target peer lookup * Replace RO access to kbuckets with channels * Add trace messages * fixup! Add trace messages * Handle each realy init separately * Receive responses in notification packets * Reset renaming of packet kind * Send responses in notification * fixup! Reset renaming of packet kind * fixup! Reinsert active request on hole punch attempt * Plug in mechanism for keeping hole punched for peer * Only give work of keeping hole punched to nodes that aren't WAN reachable * fixup! Only give work of keeping hole punched to nodes that aren't WAN reachable * Correct comment * Include nodes that discover reachable address earlier in small networks * fixup! Include nodes that discover reachable address earlier in small networks * Limit sessions with unreachable enrs * Set limit for sessions with peers with unreachable ENRs in config * Allow unlimited sessions with unreachable ENRs like in discv5.0 * Clean up fs * Update naming to match wire * Lint fixes * Doc links fix * Bug fix * Log messages fixes * Updates from nat hole punch crate * fixup! Updates from nat hole punch crate * Incorporate notification * notif sep * Incorporate notification from nat_hole_punch crate * Move hole punch trait from nat_hole_punch crate into crate * fixup! Move hole punch trait from nat_hole_punch crate into crate * Make log message more human readbable * Clean up * Stop punching holes for disconnected peers * Fix session limiter constructor bug to not write to logs on no limit and add limiter test * Fix wrong comments on message types and collect message types * Check for unused deps in CI (#1262) * Check for unused deps in CI * Bump slashing protection parking_lot version * Cherry-pick 6ee4f7f * Update github CI to latest version * Remove unused dependencies * Remove unused varaiable assignment * Restore and improve config comments * Use derive From macro * fixup! Restore and improve config comments * Restore drive-by commit to master * Return earlier from enr unreachable check * Replace parse display with dep used in lighthouse * Safeguard with const evaluation * Fix typo Co-authored-by: Divma <[email protected]> * Mark unreachable code * Allow assertions on constants * Fix clippy warnings * fixup! Allow assertions on constants * fixup! Return earlier from enr unreachable check * fixup! Fix session limiter constructor bug to not write to logs on no limit and add limiter test * fixup! Return earlier from enr unreachable check * Shorten debug message * Correct comment correction * Revert symbol * Nitpick Co-authored-by: Divma <[email protected]> * Clarify comment * Reinsert Cargo.lock in gitignore * Fix curly brace bug * remove lockfile * reduce diff * clippy * Fix typo Co-authored-by: Divma <[email protected]> * Check limit in config instead * Restore comment * Simplify docs * Drop notification already at service layer * Improve rust idiomacy * fixup! Drop notification already at service layer * Nitpick * Remove hole punch trait * Simplify bind Co-authored-by: Divma <[email protected]> * Expose unused ports range parameter in config * Fix typo Co-authored-by: Divma <[email protected]> * Fix ci for ipv6 tests * Name consistently with specs Co-authored-by: Age Manning <[email protected]> * Fix typo Co-authored-by: Age Manning <[email protected]> * Only track outgoing packets if node is behind nat * Only process relay messages if we are behind a nat * Catch malicious relay init * Clear hole punch tracker set for remaining entries * Run lint * Introduce bound on relay store * Remove redundant parameter * Keep session but drop packet that could be spoofed * Add debug info * Revert layout of hole punch code to use trait * Fix backwards compatibility of packet type Message * Remove duplicate guard * Use lru time cach for tracking sent packages * Adjust visibility, handler not alone-standing crate * Add signature for using session limiter on cache insert * Only send expired entries on channel * Remove duplicate code * Move assertion on constant outside of function * no unreachables in session enr * Avoid breaking change to lru time cache api * Change name 'session index' to name of session index type * Update docs * Update comment Co-authored-by: Kolby Moroz Liebl <[email protected]> * fixup! Update docs * Lint fixes * Lint fixes * fixup! Lint fixes * Fix docs * Tweak incorporation of SessionLimiter * Avoid clone * Lint fixes * Enable ipv6 tests * fixup! Fix merge conflicts with discv5.2 * fixup! Enable ipv6 tests * Fix test parallelisation * Add relay test for handler * Drive-by, fix param name * Drive-by, clean up test * Fix handler test parallelisation * Skip unnecessary interaction with service task * Add test for target * Remove unnecessary memory re-allocation for sessions cache * Reset previous commit * Improve type safety for notifications * Reset commit b32e750 and check sequence of initiator's enr against kbucket entry * Refactor initiator abbreviation * Trigger ping all peers on upgrade to reachable enr * Modify session management to inside the lrutimecache * Add reviewers comments * Simplify the code, name changes group handler API * Old mate fmt * Fix bug broken invariant active-requests and hole punch attempts * Update src/handler/mod.rs Co-authored-by: Emilia Hane <[email protected]> * Update src/service.rs Co-authored-by: Emilia Hane <[email protected]> * Update src/handler/mod.rs Co-authored-by: Emilia Hane <[email protected]> * Complete the renaming * Fmt --------- Co-authored-by: Emilia Hane <[email protected]> Co-authored-by: Michael Sproul <[email protected]> Co-authored-by: Divma <[email protected]> Co-authored-by: Diva M <[email protected]> Co-authored-by: Age Manning <[email protected]> Co-authored-by: Kolby Moroz Liebl <[email protected]>
1 parent 3732b3f commit 04f2dc6

File tree

23 files changed

+2308
-735
lines changed

23 files changed

+2308
-735
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Get latest version of stable rust
2020
run: rustup update stable
2121
- name: Lint code for quality and style with Clippy
22-
run: cargo clippy --workspace --tests --all-features -- -D warnings
22+
run: cargo clippy --workspace --tests --all-features -- -D warnings -A clippy::assertions_on_constants
2323
release-tests-ubuntu:
2424
runs-on: ubuntu-latest
2525
needs: cargo-fmt
@@ -50,7 +50,7 @@ jobs:
5050
- name: Get latest version of stable rust
5151
run: rustup update stable
5252
- name: Check rustdoc links
53-
run: RUSTDOCFLAGS="--deny broken_intra_doc_links" cargo doc --verbose --workspace --no-deps --document-private-items
53+
run: RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --verbose --workspace --no-deps --document-private-items
5454
cargo-udeps:
5555
name: cargo-udeps
5656
runs-on: ubuntu-latest

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ aes = { version = "0.7.5", features = ["ctr"] }
3434
aes-gcm = "0.9.4"
3535
tracing = { version = "0.1.29", features = ["log"] }
3636
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
37-
lru = "0.7.1"
37+
lru = {version = "0.7.1", default-features = false }
3838
hashlink = "0.7.0"
3939
delay_map = "0.3.0"
4040
more-asserts = "0.2.2"
41+
derive_more = { version = "0.99.17", default-features = false, features = ["from", "display", "deref", "deref_mut"] }
4142

4243
[dev-dependencies]
4344
rand_07 = { package = "rand", version = "0.7" }

src/config.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
//! A set of configuration parameters to tune the discovery protocol.
22
use crate::{
3-
kbucket::MAX_NODES_PER_BUCKET, socket::ListenConfig, Enr, Executor, PermitBanList, RateLimiter,
3+
kbucket::MAX_NODES_PER_BUCKET, Enr, Executor, ListenConfig, PermitBanList, RateLimiter,
44
RateLimiterBuilder,
55
};
6-
use std::time::Duration;
6+
7+
/// The minimum number of unreachable Sessions a node must allow. This enables the network to
8+
/// boostrap.
9+
const MIN_SESSIONS_UNREACHABLE_ENR: usize = 10;
10+
11+
use std::{ops::RangeInclusive, time::Duration};
712

813
/// Configuration parameters that define the performance of the discovery network.
914
#[derive(Clone)]
@@ -96,6 +101,15 @@ pub struct Discv5Config {
96101
/// timing support. By default, the executor that created the discv5 struct will be used.
97102
pub executor: Option<Box<dyn Executor + Send + Sync>>,
98103

104+
/// The max limit for peers with unreachable ENRs. Benevolent examples of such peers are peers
105+
/// that are discovering their externally reachable socket, nodes must assist at least one
106+
/// such peer in discovering their reachable socket via ip voting, and peers behind symmetric
107+
/// NAT. Default is no limit. Minimum is 10.
108+
pub unreachable_enr_limit: Option<usize>,
109+
110+
/// The unused port range to try and bind to when testing if this node is behind NAT based on
111+
/// observed address reported at runtime by peers.
112+
pub unused_port_range: Option<RangeInclusive<u16>>,
99113
/// Configuration for the sockets to listen on.
100114
pub listen_config: ListenConfig,
101115
}
@@ -142,6 +156,8 @@ impl Discv5ConfigBuilder {
142156
permit_ban_list: PermitBanList::default(),
143157
ban_duration: Some(Duration::from_secs(3600)), // 1 hour
144158
executor: None,
159+
unreachable_enr_limit: None,
160+
unused_port_range: None,
145161
listen_config,
146162
};
147163

@@ -302,13 +318,33 @@ impl Discv5ConfigBuilder {
302318
self
303319
}
304320

321+
/// Sets the maximum number of sessions with peers with unreachable ENRs to allow. Minimum is 1
322+
/// peer. Default is no limit.
323+
pub fn unreachable_enr_limit(&mut self, peer_limit: Option<usize>) -> &mut Self {
324+
self.config.unreachable_enr_limit = peer_limit;
325+
self
326+
}
327+
328+
/// Sets the unused port range for testing if node is behind a NAT. Default is the range
329+
/// covering user and dynamic ports.
330+
pub fn unused_port_range(
331+
&mut self,
332+
unused_port_range: Option<RangeInclusive<u16>>,
333+
) -> &mut Self {
334+
self.config.unused_port_range = unused_port_range;
335+
self
336+
}
337+
305338
pub fn build(&mut self) -> Discv5Config {
306339
// If an executor is not provided, assume a current tokio runtime is running.
307340
if self.config.executor.is_none() {
308341
self.config.executor = Some(Box::<crate::executor::TokioExecutor>::default());
309342
};
310343

311344
assert!(self.config.incoming_bucket_limit <= MAX_NODES_PER_BUCKET);
345+
if let Some(limit) = self.config.unreachable_enr_limit {
346+
assert!(limit >= MIN_SESSIONS_UNREACHABLE_ENR);
347+
}
312348

313349
self.config.clone()
314350
}

src/error.rs

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
1-
use crate::{handler::Challenge, node_info::NonContactable};
1+
use crate::{
2+
handler::Challenge,
3+
node_info::{NodeAddress, NonContactable},
4+
};
5+
use derive_more::From;
26
use rlp::DecoderError;
37
use std::fmt;
48

5-
#[derive(Debug)]
9+
#[derive(Debug, From)]
610
/// A general error that is used throughout the Discv5 library.
711
pub enum Discv5Error {
12+
/// An invalid message type was received.
13+
InvalidMessage,
814
/// An invalid ENR was received.
915
InvalidEnr,
16+
/// The limit for sessions with peers that have an unreachable ENR is reached.
17+
LimitSessionsUnreachableEnr,
1018
/// The public key type is known.
1119
UnknownPublicKey,
1220
/// The ENR key used is not supported.
21+
#[from(ignore)]
1322
KeyTypeNotSupported(&'static str),
1423
/// Failed to derive an ephemeral public key.
1524
KeyDerivationFailed,
@@ -27,25 +36,48 @@ pub enum Discv5Error {
2736
ServiceAlreadyStarted,
2837
/// A session could not be established with the remote.
2938
SessionNotEstablished,
39+
/// A session to the given peer is already established.
40+
SessionAlreadyEstablished(NodeAddress),
3041
/// An RLP decoding error occurred.
3142
RLPError(DecoderError),
3243
/// Failed to encrypt a message.
44+
#[from(ignore)]
3345
EncryptionFail(String),
3446
/// Failed to decrypt a message.
47+
#[from(ignore)]
3548
DecryptionFailed(String),
3649
/// The custom error has occurred.
50+
#[from(ignore)]
3751
Custom(&'static str),
3852
/// A generic dynamic error occurred.
53+
#[from(ignore)]
3954
Error(String),
4055
/// An IO error occurred.
4156
Io(std::io::Error),
4257
}
4358

44-
impl From<std::io::Error> for Discv5Error {
45-
fn from(err: std::io::Error) -> Discv5Error {
46-
Discv5Error::Io(err)
47-
}
59+
/// An error occurred whilst attempting to hole punch NAT.
60+
#[derive(Debug)]
61+
pub enum NatError {
62+
/// Initiator error.
63+
Initiator(Discv5Error),
64+
/// Relayer error.
65+
Relay(Discv5Error),
66+
/// Target error.
67+
Target(Discv5Error),
68+
}
69+
70+
macro_rules! impl_from_variant {
71+
($(<$($generic: ident,)+>)*, $from_type: ty, $to_type: ty, $variant: path) => {
72+
impl$(<$($generic,)+>)* From<$from_type> for $to_type {
73+
fn from(_e: $from_type) -> Self {
74+
$variant
75+
}
76+
}
77+
};
4878
}
79+
impl_from_variant!(<T,>, tokio::sync::mpsc::error::SendError<T>, Discv5Error, Self::ServiceChannelClosed);
80+
impl_from_variant!(, NonContactable, Discv5Error, Self::InvalidEnr);
4981

5082
#[derive(Debug, Clone, PartialEq, Eq)]
5183
/// Types of packet errors.
@@ -111,6 +143,9 @@ pub enum RequestError {
111143
InvalidMultiaddr(&'static str),
112144
/// Failure generating random numbers during request.
113145
EntropyFailure(&'static str),
146+
/// Malicious peer tried to initiate nat hole punching for another peer. todo(emhane): this is
147+
/// notification error.
148+
MaliciousRelayInit,
114149
}
115150

116151
#[derive(Debug, Clone, PartialEq, Eq)]

0 commit comments

Comments
 (0)