[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.
This commit is contained in:
Roman Borschel 2020-07-08 11:51:49 +02:00 committed by GitHub
parent c4a5497d2d
commit 6ad05b0ff1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 5 deletions

View File

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

View File

@ -382,13 +382,16 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
/// 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<ProtocolsHandler = THandler>,
// 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);
}
}
}
}