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:
Thomas Eizinger
2023-03-21 21:58:09 +01:00
committed by GitHub
parent 3fa10be0d5
commit f64187049d
12 changed files with 532 additions and 2 deletions

14
Cargo.lock generated
View File

@ -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"

View File

@ -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",

View File

@ -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

View File

@ -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" }

View File

@ -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;

View File

@ -0,0 +1,3 @@
# 0.1.0 - unreleased
- Initial release.

View 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" }

View 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,
}
}
}
}

View File

@ -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 {

View File

@ -1923,6 +1923,7 @@ where
}; };
match error { match error {
#[allow(deprecated)]
DialError::Banned DialError::Banned
| DialError::LocalPeerId { .. } | DialError::LocalPeerId { .. }
| DialError::InvalidPeerId { .. } | DialError::InvalidPeerId { .. }

View File

@ -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

View File

@ -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();