From c7f80f6a26d85386e1d2725759e62f0ca17e7652 Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 9 Sep 2024 13:19:48 +0200 Subject: [PATCH] Network discovery: store the remote address of the peer after finishing a successful handshake. This remote address can later by used for various tasks, like banning. Network connection pool: only look at a part of a Multiaddr to determine if an address is banned. --- .../src/connection_pool/behaviour.rs | 19 ++++++++------- network-libp2p/src/discovery/handler.rs | 24 +++++++++++++++++++ network-libp2p/src/discovery/peer_contacts.rs | 22 ++++++++++++++++- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/network-libp2p/src/connection_pool/behaviour.rs b/network-libp2p/src/connection_pool/behaviour.rs index a5ba7ab00e..5c8f08a242 100644 --- a/network-libp2p/src/connection_pool/behaviour.rs +++ b/network-libp2p/src/connection_pool/behaviour.rs @@ -28,7 +28,7 @@ use rand::{seq::IteratorRandom, thread_rng}; use void::Void; use super::Error; -use crate::discovery::peer_contacts::PeerContactBook; +use crate::discovery::{handler, peer_contacts::PeerContactBook}; /// Current state of connections and peers for connection limits #[derive(Clone, Debug)] @@ -625,12 +625,11 @@ impl Behaviour { self.peer_ids.mark_banned(peer_id); debug!(%peer_id, "Banned peer"); - // Mark its addresses as banned if we have them + // Mark its outer protocol address as banned if we have it if let Some(contact) = self.contacts.read().get(&peer_id) { - let addresses = contact.addresses(); - for address in addresses { - self.addresses.mark_banned(address.clone()); - debug!(%address, "Banned address"); + if let Some(outer_protocol_address) = contact.get_outer_protocol_address() { + debug!(address = %outer_protocol_address, "Banned address"); + self.addresses.mark_banned(outer_protocol_address); } } } @@ -893,9 +892,11 @@ impl NetworkBehaviour for Behaviour { _local_addr: &Multiaddr, remote_addr: &Multiaddr, ) -> Result<(), ConnectionDenied> { - if self.addresses.is_banned(remote_addr.clone()) { - debug!(%remote_addr, "Address is banned"); - return Err(ConnectionDenied::new(Error::BannedIp)); + if let Some(outer_protocol_address) = handler::outer_protocol_address(remote_addr) { + if self.addresses.is_banned(outer_protocol_address) { + debug!(%remote_addr, "Address is banned"); + return Err(ConnectionDenied::new(Error::BannedIp)); + } } // Get IP from multiaddress if it exists. diff --git a/network-libp2p/src/discovery/handler.rs b/network-libp2p/src/discovery/handler.rs index 7c2205e930..55b7320451 100644 --- a/network-libp2p/src/discovery/handler.rs +++ b/network-libp2p/src/discovery/handler.rs @@ -10,6 +10,7 @@ use futures_timer::Delay; use instant::Instant; use libp2p::{ identity::Keypair, + multiaddr::Protocol, swarm::{ handler::{ ConnectionEvent, DialUpgradeError, FullyNegotiatedInbound, FullyNegotiatedOutbound, @@ -173,6 +174,12 @@ impl Handler { peer_contact_book: Arc>, peer_address: Multiaddr, ) -> Self { + if let Some(peer_contact) = peer_contact_book.write().get(&peer_id) { + if let Some(outer_protocol_address) = outer_protocol_address(&peer_address) { + peer_contact.set_outer_protocol_address(outer_protocol_address); + } + } + Self { peer_id, config, @@ -244,6 +251,23 @@ impl Handler { } } +/// Extract the `/ip4/`,`/ip6/`, `/dns4/` or `/dns6/` protocol part from a `Multiaddr` +pub(crate) fn outer_protocol_address(addr: &Multiaddr) -> Option { + addr.iter() + .find(|p| { + matches!( + p, + Protocol::Dns(_) + | Protocol::Dns4(_) + | Protocol::Dns6(_) + | Protocol::Ip4(_) + | Protocol::Ip6(_) + ) + }) + .map(|p| Some(p.into())) + .unwrap_or(None) +} + impl ConnectionHandler for Handler { type FromBehaviour = (); type ToBehaviour = HandlerOutEvent; diff --git a/network-libp2p/src/discovery/peer_contacts.rs b/network-libp2p/src/discovery/peer_contacts.rs index 55020a523c..723bc667e5 100644 --- a/network-libp2p/src/discovery/peer_contacts.rs +++ b/network-libp2p/src/discovery/peer_contacts.rs @@ -185,6 +185,7 @@ impl SignedPeerContact { /// Meta information attached to peer contact info objects. This is meant to be mutable and change over time. #[derive(Clone, Debug, Serialize, Deserialize)] struct PeerContactMeta { + outer_protocol_address: Option, score: f64, } @@ -209,7 +210,10 @@ impl From for PeerContactInfo { Self { peer_id, contact, - meta: RwLock::new(PeerContactMeta { score: 0. }), + meta: RwLock::new(PeerContactMeta { + score: 0., + outer_protocol_address: None, + }), } } } @@ -273,6 +277,22 @@ impl PeerContactInfo { pub fn set_score(&self, score: f64) { self.meta.write().score = score; } + + /// Gets the outer protocol address of the peer. For example `/ip4/x.x.x.x` or `/dns4/foo.bar` + pub fn get_outer_protocol_address(&self) -> Option { + self.meta.read().outer_protocol_address.clone() + } + + /// Sets the outer protocol address of the peer once + pub fn set_outer_protocol_address(&self, addr: Multiaddr) { + self.meta + .write() + .outer_protocol_address + .get_or_insert_with(|| { + trace!(peer_id = %self.peer_id, %addr, "Set outer protocol address for peer"); + addr + }); + } } /// Main structure that holds the peer information that has been obtained or