From 6ad05b0ff1cb11ceec37cb191adb0d13feaceeb4 Mon Sep 17 00:00:00 2001 From: Roman Borschel Date: Wed, 8 Jul 2020 11:51:49 +0200 Subject: [PATCH] [libp2p-swarm] Ignore a node's own addresses on dialing. (#1646) * Ignore a node's own addresses on dialing. Dialing attempts of a local node to one of its own addresses for what appears to be a different peer ID are futile and bound to fail with an `InvalidPeerId` error. To avoid such futile dialing attempts, filter out the node's own addresses from the addresses reported by the `NetworkBehaviour` for any peer. There can be a few reasons why a `NetworkBehaviour` may think an address belongs to a different peer, e.g.: 1. In the context of e.g. `libp2p-kad`, the local node may have changed its network identity (e.g. key rotation) and "discovers" its former identity in the DHT, with the same address(es). 2. Another peer may erroneously or intentionally, possibly even maliciously, report one of the local node's addresses as its own, making the node try to connect to itself. Relates to https://github.com/paritytech/stakingops-issues/issues/18. * Remove filtering of external addresses. Since these are obtained from other peers, it would constitute an attack vector. It is furthermore usually not possible for a peer behind a NAT to dial its own external address so these are unlikely to cause `InvalidPeerId` errors as a result of a peer dialing itself under the expectation of one of its former peer IDs. --- swarm/CHANGELOG.md | 7 +++++++ swarm/src/lib.rs | 16 +++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index 8a01d483..9208db10 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -2,6 +2,13 @@ - Documentation updates. +- Ignore addresses returned by `NetworkBehaviour::addresses_of_peer` +that the `Swarm` considers to be listening addresses of the local node. This +avoids futile dialing attempts of a node to itself, which can otherwise +even happen in genuine situations, e.g. after the local node changed +its network identity and a behaviour makes a dialing attempt to a +former identity using the same addresses. + # 0.20.0 [2020-07-01] - Updated the `libp2p-core` dependency. diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 70d2d2f0..800dbc13 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -382,13 +382,16 @@ where TBehaviour: NetworkBehaviour, /// dialing attempt or `addresses_of_peer` reports no addresses, `Ok(false)` /// is returned. pub fn dial(me: &mut Self, peer_id: &PeerId) -> Result<(), DialError> { - let mut addrs = me.behaviour.addresses_of_peer(peer_id).into_iter(); - let peer = me.network.peer(peer_id.clone()); + let self_listening = &me.listened_addrs; + let mut addrs = me.behaviour.addresses_of_peer(peer_id) + .into_iter() + .filter(|a| !self_listening.contains(a)); let result = if let Some(first) = addrs.next() { let handler = me.behaviour.new_handler().into_node_handler_builder(); - peer.dial(first, addrs, handler) + me.network.peer(peer_id.clone()) + .dial(first, addrs, handler) .map(|_| ()) .map_err(DialError::ConnectionLimit) } else { @@ -696,11 +699,14 @@ where TBehaviour: NetworkBehaviour, // ongoing dialing attempt, if there is one. log::trace!("Condition for new dialing attempt to {:?} not met: {:?}", peer_id, condition); + let self_listening = &this.listened_addrs; if let Some(mut peer) = this.network.peer(peer_id.clone()).into_dialing() { let addrs = this.behaviour.addresses_of_peer(peer.id()); let mut attempt = peer.some_attempt(); - for addr in addrs { - attempt.add_address(addr); + for a in addrs { + if !self_listening.contains(&a) { + attempt.add_address(a); + } } } }