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:
Age Manning 2020-09-25 01:52:39 +00:00
parent 15638d1448
commit 28b6d921c6
6 changed files with 264 additions and 182 deletions

26
Cargo.lock generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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