Remove banned peers from DHT and track IPs (#1656)
## Issue Addressed #629 ## Proposed Changes This removes banned peers from the DHT and informs discovery to block the node_id and the known source IP's associated with this node. It has the capabilities of un banning this peer after a period of time. This also corrects the logic about banning specific IP addresses. We now use seen_ip addresses from libp2p rather than those sent to us via identify (which also include local addresses).
This commit is contained in:
parent
15638d1448
commit
28b6d921c6
26
Cargo.lock
generated
26
Cargo.lock
generated
@ -1240,9 +1240,9 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||
|
||||
[[package]]
|
||||
name = "discv5"
|
||||
version = "0.1.0-alpha.10"
|
||||
version = "0.1.0-alpha.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4cba1b485c16864edc11ccbf3abf5fbf1c26ce759ab36c32ee8e12638d50b0d"
|
||||
checksum = "c68cb1b942aadd3bb3a13620c4d831c0aa49eda988cf8bcccfdfdc7ef69504a7"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"arrayvec",
|
||||
@ -1253,17 +1253,17 @@ dependencies = [
|
||||
"hex 0.4.2",
|
||||
"hkdf",
|
||||
"lazy_static",
|
||||
"libp2p-core 0.20.1",
|
||||
"libp2p-core 0.22.1",
|
||||
"libsecp256k1",
|
||||
"log 0.4.11",
|
||||
"lru_time_cache",
|
||||
"multihash",
|
||||
"net2",
|
||||
"parking_lot 0.11.0",
|
||||
"rand 0.7.3",
|
||||
"rlp",
|
||||
"sha2 0.8.2",
|
||||
"smallvec 1.4.2",
|
||||
"socket2",
|
||||
"tokio 0.2.22",
|
||||
"uint",
|
||||
"zeroize",
|
||||
@ -2673,9 +2673,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libp2p-core"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a694fd76d7c33a45a0e6e1525e9b9b5d11127c9c94e560ac0f8abba54ed80af"
|
||||
version = "0.21.0"
|
||||
source = "git+https://github.com/sigp/rust-libp2p?rev=03f998022ce2f566a6c6e6c4206bc0ce4d45109f#03f998022ce2f566a6c6e6c4206bc0ce4d45109f"
|
||||
dependencies = [
|
||||
"asn1_der",
|
||||
"bs58",
|
||||
@ -2688,8 +2687,8 @@ dependencies = [
|
||||
"libsecp256k1",
|
||||
"log 0.4.11",
|
||||
"multihash",
|
||||
"multistream-select 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.9.2",
|
||||
"multistream-select 0.8.2 (git+https://github.com/sigp/rust-libp2p?rev=03f998022ce2f566a6c6e6c4206bc0ce4d45109f)",
|
||||
"parity-multiaddr 0.9.1",
|
||||
"parking_lot 0.10.2",
|
||||
"pin-project",
|
||||
"prost",
|
||||
@ -2707,8 +2706,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libp2p-core"
|
||||
version = "0.21.0"
|
||||
source = "git+https://github.com/sigp/rust-libp2p?rev=03f998022ce2f566a6c6e6c4206bc0ce4d45109f#03f998022ce2f566a6c6e6c4206bc0ce4d45109f"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52f13ba8c7df0768af2eb391696d562c7de88cc3a35122531aaa6a7d77754d25"
|
||||
dependencies = [
|
||||
"asn1_der",
|
||||
"bs58",
|
||||
@ -2721,8 +2721,8 @@ dependencies = [
|
||||
"libsecp256k1",
|
||||
"log 0.4.11",
|
||||
"multihash",
|
||||
"multistream-select 0.8.2 (git+https://github.com/sigp/rust-libp2p?rev=03f998022ce2f566a6c6e6c4206bc0ce4d45109f)",
|
||||
"parity-multiaddr 0.9.1",
|
||||
"multistream-select 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.9.2",
|
||||
"parking_lot 0.10.2",
|
||||
"pin-project",
|
||||
"prost",
|
||||
|
@ -40,6 +40,59 @@ mod handler;
|
||||
|
||||
const MAX_IDENTIFY_ADDRESSES: usize = 10;
|
||||
|
||||
/// Identifier of requests sent by a peer.
|
||||
pub type PeerRequestId = (ConnectionId, SubstreamId);
|
||||
|
||||
/// The types of events than can be obtained from polling the behaviour.
|
||||
#[derive(Debug)]
|
||||
pub enum BehaviourEvent<TSpec: EthSpec> {
|
||||
/// We have successfully dialed and connected to a peer.
|
||||
PeerDialed(PeerId),
|
||||
/// A peer has successfully dialed and connected to us.
|
||||
PeerConnected(PeerId),
|
||||
/// A peer has disconnected.
|
||||
PeerDisconnected(PeerId),
|
||||
/// An RPC Request that was sent failed.
|
||||
RPCFailed {
|
||||
/// The id of the failed request.
|
||||
id: RequestId,
|
||||
/// The peer to which this request was sent.
|
||||
peer_id: PeerId,
|
||||
/// The error that occurred.
|
||||
error: RPCError,
|
||||
},
|
||||
RequestReceived {
|
||||
/// The peer that sent the request.
|
||||
peer_id: PeerId,
|
||||
/// Identifier of the request. All responses to this request must use this id.
|
||||
id: PeerRequestId,
|
||||
/// Request the peer sent.
|
||||
request: Request,
|
||||
},
|
||||
ResponseReceived {
|
||||
/// Peer that sent the response.
|
||||
peer_id: PeerId,
|
||||
/// Id of the request to which the peer is responding.
|
||||
id: RequestId,
|
||||
/// Response the peer sent.
|
||||
response: Response<TSpec>,
|
||||
},
|
||||
PubsubMessage {
|
||||
/// The gossipsub message id. Used when propagating blocks after validation.
|
||||
id: MessageId,
|
||||
/// The peer from which we received this message, not the peer that published it.
|
||||
source: PeerId,
|
||||
/// The topics that this message was sent on.
|
||||
topics: Vec<TopicHash>,
|
||||
/// The message itself.
|
||||
message: PubsubMessage<TSpec>,
|
||||
},
|
||||
/// Subscribed to peer for given topic
|
||||
PeerSubscribed(PeerId, TopicHash),
|
||||
/// Inform the network to send a Status to this peer.
|
||||
StatusPeer(PeerId),
|
||||
}
|
||||
|
||||
/// Builds the network behaviour that manages the core protocols of eth2.
|
||||
/// This core behaviour is managed by `Behaviour` which adds peer management to all core
|
||||
/// behaviours.
|
||||
@ -837,13 +890,15 @@ impl<TSpec: EthSpec> NetworkBehaviour for Behaviour<TSpec> {
|
||||
|
||||
// notify the peer manager of a successful connection
|
||||
match endpoint {
|
||||
ConnectedPoint::Listener { .. } => {
|
||||
self.peer_manager.connect_ingoing(&peer_id);
|
||||
ConnectedPoint::Listener { send_back_addr, .. } => {
|
||||
self.peer_manager
|
||||
.connect_ingoing(&peer_id, send_back_addr.clone());
|
||||
self.add_event(BehaviourEvent::PeerConnected(peer_id.clone()));
|
||||
debug!(self.log, "Connection established"; "peer_id" => peer_id.to_string(), "connection" => "Incoming");
|
||||
}
|
||||
ConnectedPoint::Dialer { .. } => {
|
||||
self.peer_manager.connect_outgoing(&peer_id);
|
||||
ConnectedPoint::Dialer { address } => {
|
||||
self.peer_manager
|
||||
.connect_outgoing(&peer_id, address.clone());
|
||||
self.add_event(BehaviourEvent::PeerDialed(peer_id.clone()));
|
||||
debug!(self.log, "Connection established"; "peer_id" => peer_id.to_string(), "connection" => "Dialed");
|
||||
}
|
||||
@ -1061,59 +1116,6 @@ impl<TSpec: EthSpec> std::convert::From<Response<TSpec>> for RPCCodedResponse<TS
|
||||
}
|
||||
}
|
||||
|
||||
/// Identifier of requests sent by a peer.
|
||||
pub type PeerRequestId = (ConnectionId, SubstreamId);
|
||||
|
||||
/// The types of events than can be obtained from polling the behaviour.
|
||||
#[derive(Debug)]
|
||||
pub enum BehaviourEvent<TSpec: EthSpec> {
|
||||
/// We have successfully dialed and connected to a peer.
|
||||
PeerDialed(PeerId),
|
||||
/// A peer has successfully dialed and connected to us.
|
||||
PeerConnected(PeerId),
|
||||
/// A peer has disconnected.
|
||||
PeerDisconnected(PeerId),
|
||||
/// An RPC Request that was sent failed.
|
||||
RPCFailed {
|
||||
/// The id of the failed request.
|
||||
id: RequestId,
|
||||
/// The peer to which this request was sent.
|
||||
peer_id: PeerId,
|
||||
/// The error that occurred.
|
||||
error: RPCError,
|
||||
},
|
||||
RequestReceived {
|
||||
/// The peer that sent the request.
|
||||
peer_id: PeerId,
|
||||
/// Identifier of the request. All responses to this request must use this id.
|
||||
id: PeerRequestId,
|
||||
/// Request the peer sent.
|
||||
request: Request,
|
||||
},
|
||||
ResponseReceived {
|
||||
/// Peer that sent the response.
|
||||
peer_id: PeerId,
|
||||
/// Id of the request to which the peer is responding.
|
||||
id: RequestId,
|
||||
/// Response the peer sent.
|
||||
response: Response<TSpec>,
|
||||
},
|
||||
PubsubMessage {
|
||||
/// The gossipsub message id. Used when propagating blocks after validation.
|
||||
id: MessageId,
|
||||
/// The peer from which we received this message, not the peer that published it.
|
||||
source: PeerId,
|
||||
/// The topics that this message was sent on.
|
||||
topics: Vec<TopicHash>,
|
||||
/// The message itself.
|
||||
message: PubsubMessage<TSpec>,
|
||||
},
|
||||
/// Subscribed to peer for given topic
|
||||
PeerSubscribed(PeerId, TopicHash),
|
||||
/// Inform the network to send a Status to this peer.
|
||||
StatusPeer(PeerId),
|
||||
}
|
||||
|
||||
/// Persist metadata to disk
|
||||
pub fn save_metadata_to_disk<E: EthSpec>(dir: &PathBuf, metadata: MetaData<E>, log: &slog::Logger) {
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
|
@ -4,7 +4,7 @@ pub mod enr_ext;
|
||||
|
||||
// Allow external use of the lighthouse ENR builder
|
||||
pub use enr::{build_enr, create_enr_builder_from_config, use_or_load_enr, CombinedKey, Eth2Enr};
|
||||
pub use enr_ext::{CombinedKeyExt, EnrExt};
|
||||
pub use enr_ext::{peer_id_to_node_id, CombinedKeyExt, EnrExt};
|
||||
pub use libp2p::core::identity::Keypair;
|
||||
|
||||
use crate::metrics;
|
||||
@ -20,7 +20,7 @@ use ssz::{Decode, Encode};
|
||||
use ssz_types::BitVector;
|
||||
use std::{
|
||||
collections::{HashMap, VecDeque},
|
||||
net::SocketAddr,
|
||||
net::{IpAddr, SocketAddr},
|
||||
path::Path,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
@ -436,6 +436,33 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
enr::save_enr_to_disk(Path::new(&self.enr_dir), &self.local_enr(), &self.log);
|
||||
}
|
||||
|
||||
// Bans a peer and it's associated seen IP addresses.
|
||||
pub fn ban_peer(&mut self, peer_id: &PeerId, ip_addresses: Vec<IpAddr>) {
|
||||
// first try and convert the peer_id to a node_id.
|
||||
if let Ok(node_id) = peer_id_to_node_id(peer_id) {
|
||||
// If we could convert this peer id, remove it from the DHT and ban it from discovery.
|
||||
self.discv5.ban_node(&node_id);
|
||||
// Remove the node from the routing table.
|
||||
self.discv5.remove_node(&node_id);
|
||||
}
|
||||
|
||||
for ip_address in ip_addresses {
|
||||
self.discv5.ban_ip(ip_address);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unban_peer(&mut self, peer_id: &PeerId, ip_addresses: Vec<IpAddr>) {
|
||||
// first try and convert the peer_id to a node_id.
|
||||
if let Ok(node_id) = peer_id_to_node_id(peer_id) {
|
||||
// If we could convert this peer id, remove it from the DHT and ban it from discovery.
|
||||
self.discv5.permit_node(&node_id);
|
||||
}
|
||||
|
||||
for ip_address in ip_addresses {
|
||||
self.discv5.permit_ip(ip_address);
|
||||
}
|
||||
}
|
||||
|
||||
/* Internal Functions */
|
||||
|
||||
/// Adds a subnet query if one doesn't exist. If a subnet query already exists, this
|
||||
|
@ -194,9 +194,9 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
|
||||
// Update the PeerDB state.
|
||||
if let Some(peer_id) = ban_peer.take() {
|
||||
self.network_globals.peers.write().ban(&peer_id);
|
||||
self.ban_peer(&peer_id);
|
||||
} else if let Some(peer_id) = unban_peer.take() {
|
||||
self.network_globals.peers.write().unban(&peer_id);
|
||||
self.unban_peer(&peer_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,19 +312,22 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
|
||||
/// Sets a peer as connected as long as their reputation allows it
|
||||
/// Informs if the peer was accepted
|
||||
pub fn connect_ingoing(&mut self, peer_id: &PeerId) -> bool {
|
||||
self.connect_peer(peer_id, ConnectingType::IngoingConnected)
|
||||
pub fn connect_ingoing(&mut self, peer_id: &PeerId, multiaddr: Multiaddr) -> bool {
|
||||
self.connect_peer(peer_id, ConnectingType::IngoingConnected { multiaddr })
|
||||
}
|
||||
|
||||
/// Sets a peer as connected as long as their reputation allows it
|
||||
/// Informs if the peer was accepted
|
||||
pub fn connect_outgoing(&mut self, peer_id: &PeerId) -> bool {
|
||||
self.connect_peer(peer_id, ConnectingType::OutgoingConnected)
|
||||
pub fn connect_outgoing(&mut self, peer_id: &PeerId, multiaddr: Multiaddr) -> bool {
|
||||
self.connect_peer(peer_id, ConnectingType::OutgoingConnected { multiaddr })
|
||||
}
|
||||
|
||||
/// Updates the database informing that a peer is being disconnected.
|
||||
pub fn _disconnecting_peer(&mut self, _peer_id: &PeerId) -> bool {
|
||||
// TODO: implement
|
||||
// This informs the database that we are in the process of disconnecting the
|
||||
// peer. Currently this state only exists for a short period of time before we force the
|
||||
// disconnection.
|
||||
true
|
||||
}
|
||||
|
||||
@ -644,8 +647,12 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
peerdb.dialing_peer(peer_id);
|
||||
return true;
|
||||
}
|
||||
ConnectingType::IngoingConnected => peerdb.connect_outgoing(peer_id),
|
||||
ConnectingType::OutgoingConnected => peerdb.connect_ingoing(peer_id),
|
||||
ConnectingType::IngoingConnected { multiaddr } => {
|
||||
peerdb.connect_outgoing(peer_id, multiaddr)
|
||||
}
|
||||
ConnectingType::OutgoingConnected { multiaddr } => {
|
||||
peerdb.connect_ingoing(peer_id, multiaddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -683,12 +690,11 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
/// NOTE: This is experimental and will likely be adjusted
|
||||
fn update_peer_scores(&mut self) {
|
||||
/* Check how long have peers been in this state and update their reputations if needed */
|
||||
let mut pdb = self.network_globals.peers.write();
|
||||
|
||||
let mut to_ban_peers = Vec::new();
|
||||
let mut to_unban_peers = Vec::new();
|
||||
|
||||
for (peer_id, info) in pdb.peers_mut() {
|
||||
for (peer_id, info) in self.network_globals.peers.write().peers_mut() {
|
||||
let previous_state = info.score_state();
|
||||
// Update scores
|
||||
info.score_update();
|
||||
@ -780,14 +786,51 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
}
|
||||
// process banning peers
|
||||
for peer_id in to_ban_peers {
|
||||
pdb.ban(&peer_id);
|
||||
self.ban_peer(&peer_id);
|
||||
}
|
||||
// process unbanning peers
|
||||
for peer_id in to_unban_peers {
|
||||
pdb.unban(&peer_id);
|
||||
self.unban_peer(&peer_id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Bans a peer.
|
||||
///
|
||||
/// Records updates the peers connection status and updates the peer db as well as blocks the
|
||||
/// peer from participating in discovery and removes them from the routing table.
|
||||
fn ban_peer(&mut self, peer_id: &PeerId) {
|
||||
let mut peer_db = self.network_globals.peers.write();
|
||||
peer_db.ban(peer_id);
|
||||
let banned_ip_addresses = peer_db
|
||||
.peer_info(peer_id)
|
||||
.map(|info| {
|
||||
info.seen_addresses
|
||||
.iter()
|
||||
.filter(|ip| peer_db.is_ip_banned(ip))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
self.discovery.ban_peer(&peer_id, banned_ip_addresses);
|
||||
}
|
||||
|
||||
/// Unbans a peer.
|
||||
///
|
||||
/// Records updates the peers connection status and updates the peer db as well as removes
|
||||
/// previous bans from discovery.
|
||||
fn unban_peer(&mut self, peer_id: &PeerId) {
|
||||
let mut peer_db = self.network_globals.peers.write();
|
||||
peer_db.unban(&peer_id);
|
||||
|
||||
let seen_ip_addresses = peer_db
|
||||
.peer_info(peer_id)
|
||||
.map(|info| info.seen_addresses.iter().cloned().collect::<Vec<_>>())
|
||||
.unwrap_or_default();
|
||||
|
||||
self.discovery.unban_peer(&peer_id, seen_ip_addresses);
|
||||
}
|
||||
|
||||
/// The Peer manager's heartbeat maintains the peer count and maintains peer reputations.
|
||||
///
|
||||
/// It will request discovery queries if the peer count has not reached the desired number of
|
||||
@ -894,7 +937,13 @@ enum ConnectingType {
|
||||
/// We are in the process of dialing this peer.
|
||||
Dialing,
|
||||
/// A peer has dialed us.
|
||||
IngoingConnected,
|
||||
IngoingConnected {
|
||||
// The multiaddr the peer connected to us on.
|
||||
multiaddr: Multiaddr,
|
||||
},
|
||||
/// We have successfully dialed a peer.
|
||||
OutgoingConnected,
|
||||
OutgoingConnected {
|
||||
/// The multiaddr we dialed to reach the peer.
|
||||
multiaddr: Multiaddr,
|
||||
},
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use serde::{
|
||||
ser::{SerializeStruct, Serializer},
|
||||
Serialize,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
use std::net::IpAddr;
|
||||
use std::time::Instant;
|
||||
use types::{EthSpec, SubnetId};
|
||||
@ -24,8 +25,12 @@ pub struct PeerInfo<T: EthSpec> {
|
||||
pub client: Client,
|
||||
/// Connection status of this peer
|
||||
pub connection_status: PeerConnectionStatus,
|
||||
/// The known listening addresses of this peer.
|
||||
/// The known listening addresses of this peer. This is given by identify and can be arbitrary
|
||||
/// (including local IPs).
|
||||
pub listening_addresses: Vec<Multiaddr>,
|
||||
/// This is addresses we have physically seen and this is what we use for banning/un-banning
|
||||
/// peers.
|
||||
pub seen_addresses: HashSet<IpAddr>,
|
||||
/// The current syncing state of the peer. The state may be determined after it's initial
|
||||
/// connection.
|
||||
pub sync_status: PeerSyncStatus,
|
||||
@ -47,7 +52,8 @@ impl<TSpec: EthSpec> Default for PeerInfo<TSpec> {
|
||||
score: Score::default(),
|
||||
client: Client::default(),
|
||||
connection_status: Default::default(),
|
||||
listening_addresses: vec![],
|
||||
listening_addresses: Vec::new(),
|
||||
seen_addresses: HashSet::new(),
|
||||
sync_status: PeerSyncStatus::Unknown,
|
||||
meta_data: None,
|
||||
min_ttl: None,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::peer_info::{PeerConnectionStatus, PeerInfo};
|
||||
use super::peer_sync_status::PeerSyncStatus;
|
||||
use super::score::{Score, ScoreState};
|
||||
use crate::multiaddr::Protocol;
|
||||
use crate::multiaddr::{Multiaddr, Protocol};
|
||||
use crate::rpc::methods::MetaData;
|
||||
use crate::PeerId;
|
||||
use rand::seq::SliceRandom;
|
||||
@ -174,13 +174,14 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
}
|
||||
|
||||
fn ip_is_banned(&self, peer: &PeerInfo<TSpec>) -> bool {
|
||||
peer.listening_addresses.iter().any(|addr| {
|
||||
addr.iter().any(|p| match p {
|
||||
Protocol::Ip4(ip) => self.banned_peers_count.ip_is_banned(&ip.into()),
|
||||
Protocol::Ip6(ip) => self.banned_peers_count.ip_is_banned(&ip.into()),
|
||||
_ => false,
|
||||
})
|
||||
})
|
||||
peer.seen_addresses
|
||||
.iter()
|
||||
.any(|addr| self.banned_peers_count.ip_is_banned(addr))
|
||||
}
|
||||
|
||||
/// Returns true if the IP is banned.
|
||||
pub fn is_ip_banned(&self, ip: &IpAddr) -> bool {
|
||||
self.banned_peers_count.ip_is_banned(ip)
|
||||
}
|
||||
|
||||
/// Returns true if the Peer is either banned or in the disconnected state.
|
||||
@ -361,7 +362,7 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
}
|
||||
|
||||
/// Sets a peer as connected with an ingoing connection.
|
||||
pub fn connect_ingoing(&mut self, peer_id: &PeerId) {
|
||||
pub fn connect_ingoing(&mut self, peer_id: &PeerId, multiaddr: Multiaddr) {
|
||||
let info = self.peers.entry(peer_id.clone()).or_default();
|
||||
|
||||
if info.connection_status.is_disconnected() {
|
||||
@ -370,10 +371,19 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
self.banned_peers_count
|
||||
.remove_banned_peer(&info.connection_status);
|
||||
info.connection_status.connect_ingoing();
|
||||
|
||||
// Add the seen ip address to the peer's info
|
||||
if let Some(ip_addr) = multiaddr.iter().find_map(|p| match p {
|
||||
Protocol::Ip4(ip) => Some(ip.into()),
|
||||
Protocol::Ip6(ip) => Some(ip.into()),
|
||||
_ => None,
|
||||
}) {
|
||||
info.seen_addresses.insert(ip_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a peer as connected with an outgoing connection.
|
||||
pub fn connect_outgoing(&mut self, peer_id: &PeerId) {
|
||||
pub fn connect_outgoing(&mut self, peer_id: &PeerId, multiaddr: Multiaddr) {
|
||||
let info = self.peers.entry(peer_id.clone()).or_default();
|
||||
|
||||
if info.connection_status.is_disconnected() {
|
||||
@ -382,6 +392,15 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
self.banned_peers_count
|
||||
.remove_banned_peer(&info.connection_status);
|
||||
info.connection_status.connect_outgoing();
|
||||
|
||||
// Add the seen ip address to the peer's info
|
||||
if let Some(ip_addr) = multiaddr.iter().find_map(|p| match p {
|
||||
Protocol::Ip4(ip) => Some(ip.into()),
|
||||
Protocol::Ip6(ip) => Some(ip.into()),
|
||||
_ => None,
|
||||
}) {
|
||||
info.seen_addresses.insert(ip_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the peer as disconnected. A banned peer remains banned
|
||||
@ -411,20 +430,7 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
}
|
||||
if !info.connection_status.is_banned() {
|
||||
info.connection_status
|
||||
.ban(
|
||||
info.listening_addresses
|
||||
.iter()
|
||||
.fold(Vec::new(), |mut v, a| {
|
||||
for p in a {
|
||||
match p {
|
||||
Protocol::Ip4(ip) => v.push(ip.into()),
|
||||
Protocol::Ip6(ip) => v.push(ip.into()),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
v
|
||||
}),
|
||||
);
|
||||
.ban(info.seen_addresses.iter().cloned().collect());
|
||||
self.banned_peers_count
|
||||
.add_banned_peer(&info.connection_status);
|
||||
}
|
||||
@ -564,10 +570,10 @@ mod tests {
|
||||
|
||||
let (n_in, n_out) = (10, 20);
|
||||
for _ in 0..n_in {
|
||||
pdb.connect_ingoing(&random_peer);
|
||||
pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap());
|
||||
}
|
||||
for _ in 0..n_out {
|
||||
pdb.connect_outgoing(&random_peer);
|
||||
pdb.connect_outgoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap());
|
||||
}
|
||||
|
||||
// the peer is known
|
||||
@ -592,7 +598,7 @@ mod tests {
|
||||
|
||||
for _ in 0..MAX_DC_PEERS + 1 {
|
||||
let p = PeerId::random();
|
||||
pdb.connect_ingoing(&p);
|
||||
pdb.connect_ingoing(&p, "/ip4/0.0.0.0".parse().unwrap());
|
||||
}
|
||||
assert_eq!(pdb.disconnected_peers, 0);
|
||||
|
||||
@ -609,7 +615,7 @@ mod tests {
|
||||
|
||||
for _ in 0..MAX_BANNED_PEERS + 1 {
|
||||
let p = PeerId::random();
|
||||
pdb.connect_ingoing(&p);
|
||||
pdb.connect_ingoing(&p, "/ip4/0.0.0.0".parse().unwrap());
|
||||
}
|
||||
assert_eq!(pdb.banned_peers_count.banned_peers(), 0);
|
||||
|
||||
@ -627,9 +633,9 @@ mod tests {
|
||||
let p0 = PeerId::random();
|
||||
let p1 = PeerId::random();
|
||||
let p2 = PeerId::random();
|
||||
pdb.connect_ingoing(&p0);
|
||||
pdb.connect_ingoing(&p1);
|
||||
pdb.connect_ingoing(&p2);
|
||||
pdb.connect_ingoing(&p0, "/ip4/0.0.0.0".parse().unwrap());
|
||||
pdb.connect_ingoing(&p1, "/ip4/0.0.0.0".parse().unwrap());
|
||||
pdb.connect_ingoing(&p2, "/ip4/0.0.0.0".parse().unwrap());
|
||||
add_score(&mut pdb, &p0, 70.0);
|
||||
add_score(&mut pdb, &p1, 100.0);
|
||||
add_score(&mut pdb, &p2, 50.0);
|
||||
@ -649,9 +655,9 @@ mod tests {
|
||||
let p0 = PeerId::random();
|
||||
let p1 = PeerId::random();
|
||||
let p2 = PeerId::random();
|
||||
pdb.connect_ingoing(&p0);
|
||||
pdb.connect_ingoing(&p1);
|
||||
pdb.connect_ingoing(&p2);
|
||||
pdb.connect_ingoing(&p0, "/ip4/0.0.0.0".parse().unwrap());
|
||||
pdb.connect_ingoing(&p1, "/ip4/0.0.0.0".parse().unwrap());
|
||||
pdb.connect_ingoing(&p2, "/ip4/0.0.0.0".parse().unwrap());
|
||||
add_score(&mut pdb, &p0, 70.0);
|
||||
add_score(&mut pdb, &p1, 100.0);
|
||||
add_score(&mut pdb, &p2, 50.0);
|
||||
@ -669,18 +675,18 @@ mod tests {
|
||||
|
||||
let random_peer = PeerId::random();
|
||||
|
||||
pdb.connect_ingoing(&random_peer);
|
||||
pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap());
|
||||
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
|
||||
dbg!("1");
|
||||
|
||||
pdb.connect_ingoing(&random_peer);
|
||||
pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap());
|
||||
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
|
||||
dbg!("1");
|
||||
pdb.disconnect(&random_peer);
|
||||
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
|
||||
dbg!("1");
|
||||
|
||||
pdb.connect_outgoing(&random_peer);
|
||||
pdb.connect_outgoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap());
|
||||
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
|
||||
dbg!("1");
|
||||
pdb.disconnect(&random_peer);
|
||||
@ -711,20 +717,20 @@ mod tests {
|
||||
let random_peer2 = PeerId::random();
|
||||
let random_peer3 = PeerId::random();
|
||||
|
||||
pdb.connect_ingoing(&random_peer);
|
||||
pdb.connect_ingoing(&random_peer1);
|
||||
pdb.connect_ingoing(&random_peer2);
|
||||
pdb.connect_ingoing(&random_peer3);
|
||||
pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap());
|
||||
pdb.connect_ingoing(&random_peer1, "/ip4/0.0.0.0".parse().unwrap());
|
||||
pdb.connect_ingoing(&random_peer2, "/ip4/0.0.0.0".parse().unwrap());
|
||||
pdb.connect_ingoing(&random_peer3, "/ip4/0.0.0.0".parse().unwrap());
|
||||
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
|
||||
assert_eq!(
|
||||
pdb.banned_peers_count.banned_peers(),
|
||||
pdb.banned_peers().count()
|
||||
);
|
||||
|
||||
pdb.connect_ingoing(&random_peer);
|
||||
pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap());
|
||||
pdb.disconnect(&random_peer1);
|
||||
pdb.ban(&random_peer2);
|
||||
pdb.connect_ingoing(&random_peer3);
|
||||
pdb.connect_ingoing(&random_peer3, "/ip4/0.0.0.0".parse().unwrap());
|
||||
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
|
||||
assert_eq!(
|
||||
pdb.banned_peers_count.banned_peers(),
|
||||
@ -737,7 +743,7 @@ mod tests {
|
||||
pdb.banned_peers().count()
|
||||
);
|
||||
|
||||
pdb.connect_outgoing(&random_peer2);
|
||||
pdb.connect_outgoing(&random_peer2, "/ip4/0.0.0.0".parse().unwrap());
|
||||
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
|
||||
assert_eq!(
|
||||
pdb.banned_peers_count.banned_peers(),
|
||||
@ -751,10 +757,10 @@ mod tests {
|
||||
);
|
||||
|
||||
pdb.ban(&random_peer3);
|
||||
pdb.connect_ingoing(&random_peer1);
|
||||
pdb.connect_ingoing(&random_peer1, "/ip4/0.0.0.0".parse().unwrap());
|
||||
pdb.disconnect(&random_peer2);
|
||||
pdb.ban(&random_peer3);
|
||||
pdb.connect_ingoing(&random_peer);
|
||||
pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap());
|
||||
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
|
||||
assert_eq!(
|
||||
pdb.banned_peers_count.banned_peers(),
|
||||
@ -777,19 +783,14 @@ mod tests {
|
||||
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
|
||||
}
|
||||
|
||||
fn connect_peer_with_ips(pdb: &mut PeerDB<M>, ips: Vec<Vec<IpAddr>>) -> PeerId {
|
||||
fn connect_peer_with_ips(pdb: &mut PeerDB<M>, ips: Vec<IpAddr>) -> PeerId {
|
||||
let p = PeerId::random();
|
||||
pdb.connect_ingoing(&p);
|
||||
pdb.peers.get_mut(&p).unwrap().listening_addresses = ips
|
||||
.into_iter()
|
||||
.map(|ip_addresses| {
|
||||
|
||||
for ip in ips {
|
||||
let mut addr = Multiaddr::empty();
|
||||
for ip_address in ip_addresses {
|
||||
addr.push(Protocol::from(ip_address));
|
||||
addr.push(Protocol::from(ip));
|
||||
pdb.connect_ingoing(&p, addr);
|
||||
}
|
||||
addr
|
||||
})
|
||||
.collect();
|
||||
p
|
||||
}
|
||||
|
||||
@ -797,29 +798,29 @@ mod tests {
|
||||
fn test_ban_address() {
|
||||
let mut pdb = get_db();
|
||||
|
||||
let ip1: IpAddr = Ipv4Addr::new(1, 2, 3, 4).into();
|
||||
let ip2: IpAddr = Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8).into();
|
||||
let ip3: IpAddr = Ipv4Addr::new(1, 2, 3, 5).into();
|
||||
let ip4: IpAddr = Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 9).into();
|
||||
let ip5: IpAddr = Ipv4Addr::new(2, 2, 3, 4).into();
|
||||
let ip1 = Ipv4Addr::new(1, 2, 3, 4).into();
|
||||
let ip2 = Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8).into();
|
||||
let ip3 = Ipv4Addr::new(1, 2, 3, 5).into();
|
||||
let ip4 = Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 9).into();
|
||||
let ip5 = Ipv4Addr::new(2, 2, 3, 4).into();
|
||||
|
||||
let mut peers = Vec::new();
|
||||
for i in 0..BANNED_PEERS_PER_IP_THRESHOLD + 2 {
|
||||
peers.push(connect_peer_with_ips(
|
||||
&mut pdb,
|
||||
if i == 0 {
|
||||
vec![vec![ip1], vec![ip2]]
|
||||
vec![ip1, ip2]
|
||||
} else {
|
||||
vec![vec![ip1, ip2], vec![ip3, ip4]]
|
||||
vec![ip1, ip2, ip3, ip4]
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let p1 = connect_peer_with_ips(&mut pdb, vec![vec![ip1]]);
|
||||
let p2 = connect_peer_with_ips(&mut pdb, vec![vec![ip2, ip5]]);
|
||||
let p3 = connect_peer_with_ips(&mut pdb, vec![vec![ip3], vec![ip5]]);
|
||||
let p4 = connect_peer_with_ips(&mut pdb, vec![vec![ip5, ip4]]);
|
||||
let p5 = connect_peer_with_ips(&mut pdb, vec![vec![ip5]]);
|
||||
let p1 = connect_peer_with_ips(&mut pdb, vec![ip1]);
|
||||
let p2 = connect_peer_with_ips(&mut pdb, vec![ip2, ip5]);
|
||||
let p3 = connect_peer_with_ips(&mut pdb, vec![ip3, ip5]);
|
||||
let p4 = connect_peer_with_ips(&mut pdb, vec![ip5, ip4]);
|
||||
let p5 = connect_peer_with_ips(&mut pdb, vec![ip5]);
|
||||
|
||||
for p in &peers[..BANNED_PEERS_PER_IP_THRESHOLD + 1] {
|
||||
pdb.ban(p);
|
||||
@ -872,66 +873,63 @@ mod tests {
|
||||
|
||||
let mut peers = Vec::new();
|
||||
for _ in 0..BANNED_PEERS_PER_IP_THRESHOLD + 1 {
|
||||
peers.push(connect_peer_with_ips(&mut pdb, vec![vec![ip1]]));
|
||||
peers.push(connect_peer_with_ips(&mut pdb, vec![ip1]));
|
||||
}
|
||||
|
||||
let p1 = connect_peer_with_ips(&mut pdb, vec![vec![ip1]]);
|
||||
let p2 = connect_peer_with_ips(&mut pdb, vec![vec![ip2]]);
|
||||
let p1 = connect_peer_with_ips(&mut pdb, vec![ip1]);
|
||||
let p2 = connect_peer_with_ips(&mut pdb, vec![ip2]);
|
||||
|
||||
//ban all peers
|
||||
// ban all peers
|
||||
for p in &peers {
|
||||
pdb.ban(p);
|
||||
}
|
||||
|
||||
//check ip is banned
|
||||
// check ip is banned
|
||||
assert!(pdb.is_banned(&p1));
|
||||
assert!(!pdb.is_banned(&p2));
|
||||
|
||||
//change addresses of banned peers
|
||||
// change addresses of banned peers
|
||||
for p in &peers {
|
||||
pdb.peers.get_mut(p).unwrap().listening_addresses =
|
||||
vec![Multiaddr::empty().with(Protocol::from(ip2))];
|
||||
let seen_addresses = &mut pdb.peers.get_mut(p).unwrap().seen_addresses;
|
||||
seen_addresses.clear();
|
||||
seen_addresses.insert(ip2);
|
||||
}
|
||||
|
||||
//check still the same ip is banned
|
||||
// check still the same ip is banned
|
||||
assert!(pdb.is_banned(&p1));
|
||||
assert!(!pdb.is_banned(&p2));
|
||||
|
||||
//unban a peer
|
||||
// unban a peer
|
||||
pdb.unban(&peers[0]);
|
||||
|
||||
//check not banned anymore
|
||||
// check not banned anymore
|
||||
assert!(!pdb.is_banned(&p1));
|
||||
assert!(!pdb.is_banned(&p2));
|
||||
|
||||
//check still not banned after new ban
|
||||
pdb.ban(&peers[0]);
|
||||
assert!(!pdb.is_banned(&p1));
|
||||
assert!(!pdb.is_banned(&p2));
|
||||
|
||||
//unban and reban all peers
|
||||
// unban and reban all peers
|
||||
for p in &peers {
|
||||
pdb.unban(p);
|
||||
pdb.ban(p);
|
||||
}
|
||||
|
||||
//ip2 is now banned
|
||||
// ip2 is now banned
|
||||
assert!(!pdb.is_banned(&p1));
|
||||
assert!(pdb.is_banned(&p2));
|
||||
|
||||
//change ips back again
|
||||
// change ips back again
|
||||
for p in &peers {
|
||||
pdb.peers.get_mut(p).unwrap().listening_addresses =
|
||||
vec![Multiaddr::empty().with(Protocol::from(ip1))];
|
||||
let seen_addresses = &mut pdb.peers.get_mut(p).unwrap().seen_addresses;
|
||||
seen_addresses.clear();
|
||||
seen_addresses.insert(ip1);
|
||||
}
|
||||
|
||||
//reban every peer except one
|
||||
// reban every peer except one
|
||||
for p in &peers[1..] {
|
||||
pdb.unban(p);
|
||||
pdb.ban(p);
|
||||
}
|
||||
|
||||
//nothing is banned
|
||||
// nothing is banned
|
||||
assert!(!pdb.is_banned(&p1));
|
||||
assert!(!pdb.is_banned(&p2));
|
||||
|
||||
@ -950,7 +948,7 @@ mod tests {
|
||||
let log = build_log(slog::Level::Debug, false);
|
||||
let mut pdb: PeerDB<M> = PeerDB::new(vec![trusted_peer.clone()], &log);
|
||||
|
||||
pdb.connect_ingoing(&trusted_peer);
|
||||
pdb.connect_ingoing(&trusted_peer, "/ip4/0.0.0.0".parse().unwrap());
|
||||
|
||||
// Check trusted status and score
|
||||
assert!(pdb.peer_info(&trusted_peer).unwrap().is_trusted);
|
||||
|
Loading…
Reference in New Issue
Block a user