mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-14 02:21:21 +00:00
feat: introduce libp2p-allow-block-list
connection management module
Currently, banning peers is a first-class feature of `Swarm`. With the new connection management capabilities of `NetworkBehaviour`, we can now implement allow and block lists as a separate module. We introduce a new crate `libp2p-allow-block-list` and deprecate `Swarm::ban_peer_id` in favor of that. Related #2824. Pull-Request: #3590.
This commit is contained in:
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -2157,6 +2157,7 @@ dependencies = [
|
|||||||
"futures-timer",
|
"futures-timer",
|
||||||
"getrandom 0.2.8",
|
"getrandom 0.2.8",
|
||||||
"instant",
|
"instant",
|
||||||
|
"libp2p-allow-block-list",
|
||||||
"libp2p-autonat",
|
"libp2p-autonat",
|
||||||
"libp2p-connection-limits",
|
"libp2p-connection-limits",
|
||||||
"libp2p-core",
|
"libp2p-core",
|
||||||
@ -2193,6 +2194,19 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libp2p-allow-block-list"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"async-std",
|
||||||
|
"libp2p-core",
|
||||||
|
"libp2p-identity",
|
||||||
|
"libp2p-swarm",
|
||||||
|
"libp2p-swarm-derive",
|
||||||
|
"libp2p-swarm-test",
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libp2p-autonat"
|
name = "libp2p-autonat"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
|
@ -12,6 +12,7 @@ members = [
|
|||||||
"examples/rendezvous",
|
"examples/rendezvous",
|
||||||
"identity",
|
"identity",
|
||||||
"interop-tests",
|
"interop-tests",
|
||||||
|
"misc/allow-block-list",
|
||||||
"misc/connection-limits",
|
"misc/connection-limits",
|
||||||
"misc/keygen",
|
"misc/keygen",
|
||||||
"misc/metrics",
|
"misc/metrics",
|
||||||
|
@ -8,8 +8,12 @@
|
|||||||
To properly communicate this to users, we want them to add the dependency directly which makes the `alpha` version visible.
|
To properly communicate this to users, we want them to add the dependency directly which makes the `alpha` version visible.
|
||||||
See [PR 3580].
|
See [PR 3580].
|
||||||
|
|
||||||
|
- Introduce `libp2p::allow_block_list` module and deprecate `libp2p::Swarm::ban_peer_id`.
|
||||||
|
See [PR 3590].
|
||||||
|
|
||||||
[PR 3386]: https://github.com/libp2p/rust-libp2p/pull/3386
|
[PR 3386]: https://github.com/libp2p/rust-libp2p/pull/3386
|
||||||
[PR 3580]: https://github.com/libp2p/rust-libp2p/pull/3580
|
[PR 3580]: https://github.com/libp2p/rust-libp2p/pull/3580
|
||||||
|
[PR 3590]: https://github.com/libp2p/rust-libp2p/pull/3590
|
||||||
|
|
||||||
# 0.51.1
|
# 0.51.1
|
||||||
|
|
||||||
|
@ -96,6 +96,7 @@ futures-timer = "3.0.2" # Explicit dependency to be used in `wasm-bindgen` featu
|
|||||||
getrandom = "0.2.3" # Explicit dependency to be used in `wasm-bindgen` feature
|
getrandom = "0.2.3" # Explicit dependency to be used in `wasm-bindgen` feature
|
||||||
instant = "0.1.11" # Explicit dependency to be used in `wasm-bindgen` feature
|
instant = "0.1.11" # Explicit dependency to be used in `wasm-bindgen` feature
|
||||||
|
|
||||||
|
libp2p-allow-block-list = { version = "0.1.0", path = "../misc/allow-block-list" }
|
||||||
libp2p-autonat = { version = "0.10.0", path = "../protocols/autonat", optional = true }
|
libp2p-autonat = { version = "0.10.0", path = "../protocols/autonat", optional = true }
|
||||||
libp2p-connection-limits = { version = "0.1.0", path = "../misc/connection-limits" }
|
libp2p-connection-limits = { version = "0.1.0", path = "../misc/connection-limits" }
|
||||||
libp2p-core = { version = "0.39.0", path = "../core" }
|
libp2p-core = { version = "0.39.0", path = "../core" }
|
||||||
|
@ -40,6 +40,8 @@ pub use libp2p_core::multihash;
|
|||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use multiaddr;
|
pub use multiaddr;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use libp2p_allow_block_list as allow_block_list;
|
||||||
#[cfg(feature = "autonat")]
|
#[cfg(feature = "autonat")]
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use libp2p_autonat as autonat;
|
pub use libp2p_autonat as autonat;
|
||||||
|
3
misc/allow-block-list/CHANGELOG.md
Normal file
3
misc/allow-block-list/CHANGELOG.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# 0.1.0 - unreleased
|
||||||
|
|
||||||
|
- Initial release.
|
21
misc/allow-block-list/Cargo.toml
Normal file
21
misc/allow-block-list/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "libp2p-allow-block-list"
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.62.0"
|
||||||
|
description = "Allow/block list connection management for libp2p."
|
||||||
|
version = "0.1.0"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/libp2p/rust-libp2p"
|
||||||
|
keywords = ["peer-to-peer", "libp2p", "networking"]
|
||||||
|
categories = ["network-programming", "asynchronous"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libp2p-core = { version = "0.39.0", path = "../../core" }
|
||||||
|
libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
|
||||||
|
libp2p-identity = { version = "0.1.0", path = "../../identity", features = ["peerid"] }
|
||||||
|
void = "1"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
async-std = { version = "1.12.0", features = ["attributes"] }
|
||||||
|
libp2p-swarm-derive = { path = "../../swarm-derive" }
|
||||||
|
libp2p-swarm-test = { path = "../../swarm-test" }
|
466
misc/allow-block-list/src/lib.rs
Normal file
466
misc/allow-block-list/src/lib.rs
Normal file
@ -0,0 +1,466 @@
|
|||||||
|
// Copyright 2023 Protocol Labs.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//! A libp2p module for managing allow and blocks lists to peers.
|
||||||
|
//!
|
||||||
|
//! # Allow list example
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! # use libp2p_swarm::Swarm;
|
||||||
|
//! # use libp2p_swarm_derive::NetworkBehaviour;
|
||||||
|
//! # use libp2p_allow_block_list as allow_block_list;
|
||||||
|
//! # use libp2p_allow_block_list::AllowedPeers;
|
||||||
|
//! #
|
||||||
|
//! #[derive(NetworkBehaviour)]
|
||||||
|
//! # #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
|
||||||
|
//! struct MyBehaviour {
|
||||||
|
//! allowed_peers: allow_block_list::Behaviour<AllowedPeers>,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! # fn main() {
|
||||||
|
//! let behaviour = MyBehaviour {
|
||||||
|
//! allowed_peers: allow_block_list::Behaviour::default()
|
||||||
|
//! };
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//! # Block list example
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! # use libp2p_swarm::Swarm;
|
||||||
|
//! # use libp2p_swarm_derive::NetworkBehaviour;
|
||||||
|
//! # use libp2p_allow_block_list as allow_block_list;
|
||||||
|
//! # use libp2p_allow_block_list::BlockedPeers;
|
||||||
|
//! #
|
||||||
|
//! #[derive(NetworkBehaviour)]
|
||||||
|
//! # #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
|
||||||
|
//! struct MyBehaviour {
|
||||||
|
//! blocked_peers: allow_block_list::Behaviour<BlockedPeers>,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! # fn main() {
|
||||||
|
//! let behaviour = MyBehaviour {
|
||||||
|
//! blocked_peers: allow_block_list::Behaviour::default()
|
||||||
|
//! };
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use libp2p_core::{Endpoint, Multiaddr};
|
||||||
|
use libp2p_identity::PeerId;
|
||||||
|
use libp2p_swarm::{
|
||||||
|
dummy, CloseConnection, ConnectionDenied, ConnectionId, FromSwarm, NetworkBehaviour,
|
||||||
|
NetworkBehaviourAction, PollParameters, THandler, THandlerInEvent, THandlerOutEvent,
|
||||||
|
};
|
||||||
|
use std::collections::{HashSet, VecDeque};
|
||||||
|
use std::fmt;
|
||||||
|
use std::task::{Context, Poll, Waker};
|
||||||
|
use void::Void;
|
||||||
|
|
||||||
|
/// A [`NetworkBehaviour`] that can act as an allow or block list.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct Behaviour<S> {
|
||||||
|
state: S,
|
||||||
|
close_connections: VecDeque<PeerId>,
|
||||||
|
waker: Option<Waker>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of explicitly allowed peers.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct AllowedPeers {
|
||||||
|
peers: HashSet<PeerId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of explicitly blocked peers.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct BlockedPeers {
|
||||||
|
peers: HashSet<PeerId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Behaviour<AllowedPeers> {
|
||||||
|
/// Allow connections to the given peer.
|
||||||
|
pub fn allow_peer(&mut self, peer: PeerId) {
|
||||||
|
self.state.peers.insert(peer);
|
||||||
|
if let Some(waker) = self.waker.take() {
|
||||||
|
waker.wake()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disallow connections to the given peer.
|
||||||
|
///
|
||||||
|
/// All active connections to this peer will be closed immediately.
|
||||||
|
pub fn disallow_peer(&mut self, peer: PeerId) {
|
||||||
|
self.state.peers.insert(peer);
|
||||||
|
self.close_connections.push_back(peer);
|
||||||
|
if let Some(waker) = self.waker.take() {
|
||||||
|
waker.wake()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Behaviour<BlockedPeers> {
|
||||||
|
/// Block connections to a given peer.
|
||||||
|
///
|
||||||
|
/// All active connections to this peer will be closed immediately.
|
||||||
|
pub fn block_peer(&mut self, peer: PeerId) {
|
||||||
|
self.state.peers.insert(peer);
|
||||||
|
self.close_connections.push_back(peer);
|
||||||
|
if let Some(waker) = self.waker.take() {
|
||||||
|
waker.wake()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unblock connections to a given peer.
|
||||||
|
pub fn unblock_peer(&mut self, peer: PeerId) {
|
||||||
|
self.state.peers.insert(peer);
|
||||||
|
if let Some(waker) = self.waker.take() {
|
||||||
|
waker.wake()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A connection to this peer is not explicitly allowed and was thus [`denied`](ConnectionDenied).
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NotAllowed {
|
||||||
|
peer: PeerId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for NotAllowed {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "peer {} is not in the allow list", self.peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for NotAllowed {}
|
||||||
|
|
||||||
|
/// A connection to this peer was explicitly blocked and was thus [`denied`](ConnectionDenied).
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Blocked {
|
||||||
|
peer: PeerId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Blocked {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "peer {} is in the block list", self.peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Blocked {}
|
||||||
|
|
||||||
|
trait Enforce: 'static {
|
||||||
|
fn enforce(&self, peer: &PeerId) -> Result<(), ConnectionDenied>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Enforce for AllowedPeers {
|
||||||
|
fn enforce(&self, peer: &PeerId) -> Result<(), ConnectionDenied> {
|
||||||
|
if !self.peers.contains(peer) {
|
||||||
|
return Err(ConnectionDenied::new(NotAllowed { peer: *peer }));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Enforce for BlockedPeers {
|
||||||
|
fn enforce(&self, peer: &PeerId) -> Result<(), ConnectionDenied> {
|
||||||
|
if self.peers.contains(peer) {
|
||||||
|
return Err(ConnectionDenied::new(Blocked { peer: *peer }));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> NetworkBehaviour for Behaviour<S>
|
||||||
|
where
|
||||||
|
S: Enforce,
|
||||||
|
{
|
||||||
|
type ConnectionHandler = dummy::ConnectionHandler;
|
||||||
|
type OutEvent = Void;
|
||||||
|
|
||||||
|
fn handle_established_inbound_connection(
|
||||||
|
&mut self,
|
||||||
|
_: ConnectionId,
|
||||||
|
peer: PeerId,
|
||||||
|
_: &Multiaddr,
|
||||||
|
_: &Multiaddr,
|
||||||
|
) -> Result<THandler<Self>, ConnectionDenied> {
|
||||||
|
self.state.enforce(&peer)?;
|
||||||
|
|
||||||
|
Ok(dummy::ConnectionHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_pending_outbound_connection(
|
||||||
|
&mut self,
|
||||||
|
_: ConnectionId,
|
||||||
|
peer: Option<PeerId>,
|
||||||
|
_: &[Multiaddr],
|
||||||
|
_: Endpoint,
|
||||||
|
) -> Result<Vec<Multiaddr>, ConnectionDenied> {
|
||||||
|
if let Some(peer) = peer {
|
||||||
|
self.state.enforce(&peer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_established_outbound_connection(
|
||||||
|
&mut self,
|
||||||
|
_: ConnectionId,
|
||||||
|
peer: PeerId,
|
||||||
|
_: &Multiaddr,
|
||||||
|
_: Endpoint,
|
||||||
|
) -> Result<THandler<Self>, ConnectionDenied> {
|
||||||
|
self.state.enforce(&peer)?;
|
||||||
|
|
||||||
|
Ok(dummy::ConnectionHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
|
||||||
|
match event {
|
||||||
|
FromSwarm::ConnectionClosed(_) => {}
|
||||||
|
FromSwarm::ConnectionEstablished(_) => {}
|
||||||
|
FromSwarm::AddressChange(_) => {}
|
||||||
|
FromSwarm::DialFailure(_) => {}
|
||||||
|
FromSwarm::ListenFailure(_) => {}
|
||||||
|
FromSwarm::NewListener(_) => {}
|
||||||
|
FromSwarm::NewListenAddr(_) => {}
|
||||||
|
FromSwarm::ExpiredListenAddr(_) => {}
|
||||||
|
FromSwarm::ListenerError(_) => {}
|
||||||
|
FromSwarm::ListenerClosed(_) => {}
|
||||||
|
FromSwarm::NewExternalAddr(_) => {}
|
||||||
|
FromSwarm::ExpiredExternalAddr(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_connection_handler_event(
|
||||||
|
&mut self,
|
||||||
|
_id: PeerId,
|
||||||
|
_: ConnectionId,
|
||||||
|
event: THandlerOutEvent<Self>,
|
||||||
|
) {
|
||||||
|
void::unreachable(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(
|
||||||
|
&mut self,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
_: &mut impl PollParameters,
|
||||||
|
) -> Poll<NetworkBehaviourAction<Self::OutEvent, THandlerInEvent<Self>>> {
|
||||||
|
if let Some(peer) = self.close_connections.pop_front() {
|
||||||
|
return Poll::Ready(NetworkBehaviourAction::CloseConnection {
|
||||||
|
peer_id: peer,
|
||||||
|
connection: CloseConnection::All,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.waker = Some(cx.waker().clone());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use libp2p_swarm::{dial_opts::DialOpts, DialError, ListenError, Swarm, SwarmEvent};
|
||||||
|
use libp2p_swarm_test::SwarmExt;
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn cannot_dial_blocked_peer() {
|
||||||
|
let mut dialer = Swarm::new_ephemeral(|_| Behaviour::<BlockedPeers>::new());
|
||||||
|
let mut listener = Swarm::new_ephemeral(|_| Behaviour::<BlockedPeers>::new());
|
||||||
|
listener.listen().await;
|
||||||
|
|
||||||
|
dialer
|
||||||
|
.behaviour_mut()
|
||||||
|
.list
|
||||||
|
.block_peer(*listener.local_peer_id());
|
||||||
|
|
||||||
|
let DialError::Denied { cause } = dial(&mut dialer, &listener).unwrap_err() else {
|
||||||
|
panic!("unexpected dial error")
|
||||||
|
};
|
||||||
|
assert!(cause.downcast::<Blocked>().is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn blocked_peer_cannot_dial_us() {
|
||||||
|
let mut dialer = Swarm::new_ephemeral(|_| Behaviour::<BlockedPeers>::new());
|
||||||
|
let mut listener = Swarm::new_ephemeral(|_| Behaviour::<BlockedPeers>::new());
|
||||||
|
listener.listen().await;
|
||||||
|
|
||||||
|
listener
|
||||||
|
.behaviour_mut()
|
||||||
|
.list
|
||||||
|
.block_peer(*dialer.local_peer_id());
|
||||||
|
dial(&mut dialer, &listener).unwrap();
|
||||||
|
async_std::task::spawn(dialer.loop_on_next());
|
||||||
|
|
||||||
|
let cause = listener
|
||||||
|
.wait(|e| match e {
|
||||||
|
SwarmEvent::IncomingConnectionError {
|
||||||
|
error: ListenError::Denied { cause },
|
||||||
|
..
|
||||||
|
} => Some(cause),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
assert!(cause.downcast::<Blocked>().is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn connections_get_closed_upon_blocked() {
|
||||||
|
let mut dialer = Swarm::new_ephemeral(|_| Behaviour::<BlockedPeers>::new());
|
||||||
|
let mut listener = Swarm::new_ephemeral(|_| Behaviour::<BlockedPeers>::new());
|
||||||
|
listener.listen().await;
|
||||||
|
dialer.connect(&mut listener).await;
|
||||||
|
|
||||||
|
dialer
|
||||||
|
.behaviour_mut()
|
||||||
|
.list
|
||||||
|
.block_peer(*listener.local_peer_id());
|
||||||
|
|
||||||
|
let (
|
||||||
|
[SwarmEvent::ConnectionClosed { peer_id: closed_dialer_peer, .. }],
|
||||||
|
[SwarmEvent::ConnectionClosed { peer_id: closed_listener_peer, .. }]
|
||||||
|
) = libp2p_swarm_test::drive(&mut dialer, &mut listener).await else {
|
||||||
|
panic!("unexpected events")
|
||||||
|
};
|
||||||
|
assert_eq!(closed_dialer_peer, *listener.local_peer_id());
|
||||||
|
assert_eq!(closed_listener_peer, *dialer.local_peer_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn cannot_dial_peer_unless_allowed() {
|
||||||
|
let mut dialer = Swarm::new_ephemeral(|_| Behaviour::<AllowedPeers>::new());
|
||||||
|
let mut listener = Swarm::new_ephemeral(|_| Behaviour::<AllowedPeers>::new());
|
||||||
|
listener.listen().await;
|
||||||
|
|
||||||
|
let DialError::Denied { cause } = dial(&mut dialer, &listener).unwrap_err() else {
|
||||||
|
panic!("unexpected dial error")
|
||||||
|
};
|
||||||
|
assert!(cause.downcast::<NotAllowed>().is_ok());
|
||||||
|
|
||||||
|
dialer
|
||||||
|
.behaviour_mut()
|
||||||
|
.list
|
||||||
|
.allow_peer(*listener.local_peer_id());
|
||||||
|
assert!(dial(&mut dialer, &listener).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn not_allowed_peer_cannot_dial_us() {
|
||||||
|
let mut dialer = Swarm::new_ephemeral(|_| Behaviour::<AllowedPeers>::new());
|
||||||
|
let mut listener = Swarm::new_ephemeral(|_| Behaviour::<AllowedPeers>::new());
|
||||||
|
listener.listen().await;
|
||||||
|
|
||||||
|
dialer
|
||||||
|
.dial(
|
||||||
|
DialOpts::unknown_peer_id()
|
||||||
|
.address(
|
||||||
|
listener
|
||||||
|
.external_addresses()
|
||||||
|
.map(|a| a.addr.clone())
|
||||||
|
.next()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let (
|
||||||
|
[SwarmEvent::OutgoingConnectionError { error: DialError::Denied { cause: outgoing_cause }, .. }],
|
||||||
|
[_, _, _, SwarmEvent::IncomingConnectionError { error: ListenError::Denied { cause: incoming_cause }, .. }],
|
||||||
|
) = libp2p_swarm_test::drive(&mut dialer, &mut listener).await else {
|
||||||
|
panic!("unexpected events")
|
||||||
|
};
|
||||||
|
assert!(outgoing_cause.downcast::<NotAllowed>().is_ok());
|
||||||
|
assert!(incoming_cause.downcast::<NotAllowed>().is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn connections_get_closed_upon_disallow() {
|
||||||
|
let mut dialer = Swarm::new_ephemeral(|_| Behaviour::<AllowedPeers>::new());
|
||||||
|
let mut listener = Swarm::new_ephemeral(|_| Behaviour::<AllowedPeers>::new());
|
||||||
|
listener.listen().await;
|
||||||
|
dialer
|
||||||
|
.behaviour_mut()
|
||||||
|
.list
|
||||||
|
.allow_peer(*listener.local_peer_id());
|
||||||
|
listener
|
||||||
|
.behaviour_mut()
|
||||||
|
.list
|
||||||
|
.allow_peer(*dialer.local_peer_id());
|
||||||
|
|
||||||
|
dialer.connect(&mut listener).await;
|
||||||
|
|
||||||
|
dialer
|
||||||
|
.behaviour_mut()
|
||||||
|
.list
|
||||||
|
.disallow_peer(*listener.local_peer_id());
|
||||||
|
let (
|
||||||
|
[SwarmEvent::ConnectionClosed { peer_id: closed_dialer_peer, .. }],
|
||||||
|
[SwarmEvent::ConnectionClosed { peer_id: closed_listener_peer, .. }]
|
||||||
|
) = libp2p_swarm_test::drive(&mut dialer, &mut listener).await else {
|
||||||
|
panic!("unexpected events")
|
||||||
|
};
|
||||||
|
assert_eq!(closed_dialer_peer, *listener.local_peer_id());
|
||||||
|
assert_eq!(closed_listener_peer, *dialer.local_peer_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dial<S>(
|
||||||
|
dialer: &mut Swarm<Behaviour<S>>,
|
||||||
|
listener: &Swarm<Behaviour<S>>,
|
||||||
|
) -> Result<(), DialError>
|
||||||
|
where
|
||||||
|
S: Enforce,
|
||||||
|
{
|
||||||
|
dialer.dial(
|
||||||
|
DialOpts::peer_id(*listener.local_peer_id())
|
||||||
|
.addresses(
|
||||||
|
listener
|
||||||
|
.external_addresses()
|
||||||
|
.map(|a| a.addr.clone())
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(libp2p_swarm_derive::NetworkBehaviour)]
|
||||||
|
#[behaviour(prelude = "libp2p_swarm::derive_prelude")]
|
||||||
|
struct Behaviour<S> {
|
||||||
|
list: super::Behaviour<S>,
|
||||||
|
keep_alive: libp2p_swarm::keep_alive::Behaviour,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> Behaviour<S>
|
||||||
|
where
|
||||||
|
S: Default,
|
||||||
|
{
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
list: super::Behaviour {
|
||||||
|
waker: None,
|
||||||
|
close_connections: VecDeque::new(),
|
||||||
|
state: S::default(),
|
||||||
|
},
|
||||||
|
keep_alive: libp2p_swarm::keep_alive::Behaviour,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -223,7 +223,7 @@ impl<TBvEv, THandleErr> super::Recorder<libp2p_swarm::SwarmEvent<TBvEv, THandleE
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(deprecated)]
|
||||||
libp2p_swarm::DialError::Banned => record(OutgoingConnectionError::Banned),
|
libp2p_swarm::DialError::Banned => record(OutgoingConnectionError::Banned),
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
libp2p_swarm::DialError::ConnectionLimit(_) => {
|
libp2p_swarm::DialError::ConnectionLimit(_) => {
|
||||||
@ -250,6 +250,7 @@ impl<TBvEv, THandleErr> super::Recorder<libp2p_swarm::SwarmEvent<TBvEv, THandleE
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
#[allow(deprecated)]
|
||||||
libp2p_swarm::SwarmEvent::BannedPeer { endpoint, .. } => {
|
libp2p_swarm::SwarmEvent::BannedPeer { endpoint, .. } => {
|
||||||
self.connected_to_banned_peer
|
self.connected_to_banned_peer
|
||||||
.get_or_create(&AddressLabels {
|
.get_or_create(&AddressLabels {
|
||||||
|
@ -1923,6 +1923,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
match error {
|
match error {
|
||||||
|
#[allow(deprecated)]
|
||||||
DialError::Banned
|
DialError::Banned
|
||||||
| DialError::LocalPeerId { .. }
|
| DialError::LocalPeerId { .. }
|
||||||
| DialError::InvalidPeerId { .. }
|
| DialError::InvalidPeerId { .. }
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# 0.42.1 [unreleased]
|
# 0.42.1 - unreleased
|
||||||
|
|
||||||
- Deprecate `ConnectionLimits` in favor of `libp2p::connection_limits`.
|
- Deprecate `ConnectionLimits` in favor of `libp2p::connection_limits`.
|
||||||
See [PR 3386].
|
See [PR 3386].
|
||||||
@ -6,8 +6,12 @@
|
|||||||
- Introduce `ConnectionId::new_unchecked` to allow for more sophisticated, manual tests of `NetworkBehaviour`.
|
- Introduce `ConnectionId::new_unchecked` to allow for more sophisticated, manual tests of `NetworkBehaviour`.
|
||||||
See [PR 3652].
|
See [PR 3652].
|
||||||
|
|
||||||
|
- Deprecate `Swarm::ban_peer_id` in favor of the new `libp2p::allow_block_list` module.
|
||||||
|
See [PR 3590].
|
||||||
|
|
||||||
[PR 3386]: https://github.com/libp2p/rust-libp2p/pull/3386
|
[PR 3386]: https://github.com/libp2p/rust-libp2p/pull/3386
|
||||||
[PR 3652]: https://github.com/libp2p/rust-libp2p/pull/3652
|
[PR 3652]: https://github.com/libp2p/rust-libp2p/pull/3652
|
||||||
|
[PR 3590]: https://github.com/libp2p/rust-libp2p/pull/3590
|
||||||
|
|
||||||
# 0.42.0
|
# 0.42.0
|
||||||
|
|
||||||
|
@ -251,6 +251,7 @@ pub enum SwarmEvent<TBehaviourOutEvent, THandlerErr> {
|
|||||||
error: DialError,
|
error: DialError,
|
||||||
},
|
},
|
||||||
/// We connected to a peer, but we immediately closed the connection because that peer is banned.
|
/// We connected to a peer, but we immediately closed the connection because that peer is banned.
|
||||||
|
#[deprecated(note = "Use `libp2p::allow_block_list` instead.", since = "0.42.1")]
|
||||||
BannedPeer {
|
BannedPeer {
|
||||||
/// Identity of the banned peer.
|
/// Identity of the banned peer.
|
||||||
peer_id: PeerId,
|
peer_id: PeerId,
|
||||||
@ -556,6 +557,7 @@ where
|
|||||||
if let Some(peer_id) = peer_id {
|
if let Some(peer_id) = peer_id {
|
||||||
// Check if peer is banned.
|
// Check if peer is banned.
|
||||||
if self.banned_peers.contains(&peer_id) {
|
if self.banned_peers.contains(&peer_id) {
|
||||||
|
#[allow(deprecated)]
|
||||||
let error = DialError::Banned;
|
let error = DialError::Banned;
|
||||||
self.behaviour
|
self.behaviour
|
||||||
.on_swarm_event(FromSwarm::DialFailure(DialFailure {
|
.on_swarm_event(FromSwarm::DialFailure(DialFailure {
|
||||||
@ -738,6 +740,7 @@ where
|
|||||||
///
|
///
|
||||||
/// Any incoming connection and any dialing attempt will immediately be rejected.
|
/// Any incoming connection and any dialing attempt will immediately be rejected.
|
||||||
/// This function has no effect if the peer is already banned.
|
/// This function has no effect if the peer is already banned.
|
||||||
|
#[deprecated(note = "Use `libp2p::allow_block_list` instead.", since = "0.42.1")]
|
||||||
pub fn ban_peer_id(&mut self, peer_id: PeerId) {
|
pub fn ban_peer_id(&mut self, peer_id: PeerId) {
|
||||||
if self.banned_peers.insert(peer_id) {
|
if self.banned_peers.insert(peer_id) {
|
||||||
// Note that established connections to the now banned peer are closed but not
|
// Note that established connections to the now banned peer are closed but not
|
||||||
@ -749,6 +752,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Unbans a peer.
|
/// Unbans a peer.
|
||||||
|
#[deprecated(note = "Use `libp2p::allow_block_list` instead.", since = "0.42.1")]
|
||||||
pub fn unban_peer_id(&mut self, peer_id: PeerId) {
|
pub fn unban_peer_id(&mut self, peer_id: PeerId) {
|
||||||
self.banned_peers.remove(&peer_id);
|
self.banned_peers.remove(&peer_id);
|
||||||
}
|
}
|
||||||
@ -809,6 +813,7 @@ where
|
|||||||
established_in,
|
established_in,
|
||||||
} => {
|
} => {
|
||||||
if self.banned_peers.contains(&peer_id) {
|
if self.banned_peers.contains(&peer_id) {
|
||||||
|
#[allow(deprecated)]
|
||||||
return Some(SwarmEvent::BannedPeer { peer_id, endpoint });
|
return Some(SwarmEvent::BannedPeer { peer_id, endpoint });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1716,6 +1721,7 @@ where
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DialError {
|
pub enum DialError {
|
||||||
/// The peer is currently banned.
|
/// The peer is currently banned.
|
||||||
|
#[deprecated(note = "Use `libp2p::allow_block_list` instead.", since = "0.42.1")]
|
||||||
Banned,
|
Banned,
|
||||||
/// The configured limit for simultaneous outgoing connections
|
/// The configured limit for simultaneous outgoing connections
|
||||||
/// has been reached.
|
/// has been reached.
|
||||||
@ -1776,6 +1782,7 @@ impl fmt::Display for DialError {
|
|||||||
f,
|
f,
|
||||||
"Dial error: tried to dial local peer id at {endpoint:?}."
|
"Dial error: tried to dial local peer id at {endpoint:?}."
|
||||||
),
|
),
|
||||||
|
#[allow(deprecated)]
|
||||||
DialError::Banned => write!(f, "Dial error: peer is banned."),
|
DialError::Banned => write!(f, "Dial error: peer is banned."),
|
||||||
DialError::DialPeerConditionFalse(c) => {
|
DialError::DialPeerConditionFalse(c) => {
|
||||||
write!(f, "Dial error: condition {c:?} for dialing peer was false.")
|
write!(f, "Dial error: condition {c:?} for dialing peer was false.")
|
||||||
@ -1827,6 +1834,7 @@ impl error::Error for DialError {
|
|||||||
DialError::ConnectionLimit(err) => Some(err),
|
DialError::ConnectionLimit(err) => Some(err),
|
||||||
DialError::LocalPeerId { .. } => None,
|
DialError::LocalPeerId { .. } => None,
|
||||||
DialError::NoAddresses => None,
|
DialError::NoAddresses => None,
|
||||||
|
#[allow(deprecated)]
|
||||||
DialError::Banned => None,
|
DialError::Banned => None,
|
||||||
DialError::DialPeerConditionFalse(_) => None,
|
DialError::DialPeerConditionFalse(_) => None,
|
||||||
DialError::Aborted => None,
|
DialError::Aborted => None,
|
||||||
@ -1926,6 +1934,9 @@ impl error::Error for ListenError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A connection was denied.
|
||||||
|
///
|
||||||
|
/// To figure out which [`NetworkBehaviour`] denied the connection, use [`ConnectionDenied::downcast`].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ConnectionDenied {
|
pub struct ConnectionDenied {
|
||||||
inner: Box<dyn error::Error + Send + Sync + 'static>,
|
inner: Box<dyn error::Error + Send + Sync + 'static>,
|
||||||
@ -2117,6 +2128,7 @@ mod tests {
|
|||||||
/// [`FromSwarm::ConnectionEstablished`], [`FromSwarm::ConnectionClosed`]
|
/// [`FromSwarm::ConnectionEstablished`], [`FromSwarm::ConnectionClosed`]
|
||||||
/// calls should be registered.
|
/// calls should be registered.
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(deprecated)]
|
||||||
fn test_connect_disconnect_ban() {
|
fn test_connect_disconnect_ban() {
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user