Skip to content

Commit

Permalink
Ban peer after disconnect (#1358)
Browse files Browse the repository at this point in the history
* Ban peer after disconnect

* Just do it all the time

* Need to call `gossip_remove_desired_all` otherwise there's a mismatch
  • Loading branch information
tomaka authored Nov 18, 2023
1 parent 9a540a5 commit 9502607
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 16 deletions.
15 changes: 15 additions & 0 deletions lib/src/network/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,21 @@ where
&self.inner[id].address
}

/// Returns the number of connections with the given peer.
///
/// Both connections that have and have not finished their handshaking phase are considered.
pub fn num_potential_and_established_connections(&self, peer_id: &PeerId) -> usize {
let Some(&peer_index) = self.peers_by_peer_id.get(peer_id) else {
return 0;
};

self.connections_by_peer_id
.range(
(peer_index, ConnectionId::min_value())..=(peer_index, ConnectionId::max_value()),
)
.count()
}

/// Pulls a message that must be sent to a connection.
///
/// The message must be passed to [`SingleStreamConnectionTask::inject_coordinator_message`]
Expand Down
73 changes: 57 additions & 16 deletions light-base/src/network_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1526,6 +1526,7 @@ async fn background_task<TPlat: PlatformRef>(mut task: BackgroundTask<TPlat>) {

task.peering_strategy
.remove_address(expected_peer_id, remote_addr.as_ref());
// TODO: if Bob says that its address is the same as Alice's, and we try to connect to both Alice and Bob, then the Bob connection will reach this path and set Alice's address as connected even though it's already connected; this will later cause a state mismatch when disconnecting
let _ = task.peering_strategy.insert_or_set_connected_address(
&peer_id,
remote_addr.clone().into_vec(),
Expand All @@ -1536,27 +1537,67 @@ async fn background_task<TPlat: PlatformRef>(mut task: BackgroundTask<TPlat>) {
}
}
WakeUpReason::NetworkEvent(service::Event::PreHandshakeDisconnected {
address,
expected_peer_id,
expected_peer_id: Some(_),
..
}) => {
if let Some(expected_peer_id) = expected_peer_id {
task.peering_strategy
.disconnect_addr(&expected_peer_id, &address)
.unwrap();
let address = Multiaddr::try_from(address).unwrap();
log::debug!(target: "network", "Connections({}, {}) => Shutdown(handshake_finished=false)", expected_peer_id, address);
}
}
WakeUpReason::NetworkEvent(service::Event::Disconnected {
address, peer_id, ..
}) => {
})
| WakeUpReason::NetworkEvent(service::Event::Disconnected { .. }) => {
let (address, peer_id, handshake_finished) = match wake_up_reason {
WakeUpReason::NetworkEvent(service::Event::PreHandshakeDisconnected {
address,
expected_peer_id: Some(peer_id),
..
}) => (address, peer_id, false),
WakeUpReason::NetworkEvent(service::Event::Disconnected {
address,
peer_id,
..
}) => (address, peer_id, true),
_ => unreachable!(),
};

task.peering_strategy
.disconnect_addr(&peer_id, &address)
.unwrap();

let address = Multiaddr::try_from(address).unwrap();
log::debug!(target: "network", "Connections({}, {}) => Shutdown(handshake_finished=true)", peer_id, address);
log::debug!(target: "network", "Connections({}, {}) => Shutdown(handshake_finished={handshake_finished:?})", peer_id, address);

// Ban the peer in order to avoid trying over and over again the same address(es).
// Even if the handshake was finished, it is possible that the peer simply shuts
// down connections immediately after it has been opened, hence the ban.
// Due to race conditions and peerid mismatches, it is possible that there is
// another existing connection or connection attempt with that same peer. However,
// it is not possible to be sure that we will reach 0 connections or connection
// attempts, and thus we ban the peer every time.
let ban_duration = Duration::from_secs(5);
task.network.gossip_remove_desired_all(
&peer_id,
service::GossipKind::ConsensusTransactions,
);
for (&chain_id, what_happened) in task
.peering_strategy
.unassign_slots_and_ban(&peer_id, task.platform.now() + ban_duration)
{
if matches!(
what_happened,
basic_peering_strategy::UnassignSlotsAndBan::Banned { had_slot: true }
) {
log::debug!(
target: "network",
"Slots({}) ∌ {} (reason=pre-handshake-disconnect, ban-duration={:?})",
&task.network[chain_id].log_name,
peer_id,
ban_duration
);
}
}
}
WakeUpReason::NetworkEvent(service::Event::PreHandshakeDisconnected {
expected_peer_id: None,
..
}) => {
// This path can't be reached as we always set an expected peer id when creating
// a connection.
debug_assert!(false);
}
WakeUpReason::NetworkEvent(service::Event::BlockAnnounce {
chain_id,
Expand Down
1 change: 1 addition & 0 deletions wasm-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Changed

- Addresses that are not supported by the host platform are now ignored during the discovery process. For example, TCP/IP connections are ignored while in a browser. This avoids populating the address book with peers that we know we can't connect to anyway. ([#1359](https://github.com/smol-dot/smoldot/pull/1359), [#1360](https://github.com/smol-dot/smoldot/pull/1360))
- Smoldot will no longer try to connect to the same address over and over again. ([#1358](https://github.com/smol-dot/smoldot/pull/1358))

## 2.0.10 - 2023-11-17

Expand Down

0 comments on commit 9502607

Please sign in to comment.