Skip to content

Commit

Permalink
feat(identify): add hide_listen_addrs config option (#5507)
Browse files Browse the repository at this point in the history
## Description

Implements #4010, which was closed. It was closed because it appeared
that the Identify specification doesn't dictate this feature. But, in
the discussion on the specs repo
(libp2p/specs#597) it is mentioned that this
might very well be an implementation detail.

This PR introduces a `hide_listen_addrs` flag that will prevent our
listen addresses to be included, effectively only sharing our external
addresses.

<!--
Please write a summary of your changes and why you made them.
This section will appear as the commit message after merging.
Please craft it accordingly.
For a quick primer on good commit messages, check out this blog post:
https://cbea.ms/git-commit/

Please include any relevant issues in here, for example:

Related https://github.com/libp2p/rust-libp2p/issues/ABCD.
Fixes https://github.com/libp2p/rust-libp2p/issues/XYZ.
-->

## Notes & open questions

An alternative implementation would be to allow us to filter the
addresses we are sending out, by providing a closure I imagine.

<!--
Any notes, remarks or open questions you have to make about the PR which
don't need to go into the final commit message.
-->

## Change checklist

<!-- Please add a Changelog entry in the appropriate crates and bump the
crate versions if needed. See
<https://github.com/libp2p/rust-libp2p/blob/master/docs/release.md#development-between-releases>-->

- [x] I have performed a self-review of my own code
- [x] I have made corresponding changes to the documentation
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] A changelog entry has been made in the appropriate crates

---------

Co-authored-by: Darius Clark <dariusc93@users.noreply.github.com>
  • Loading branch information
b-zee and dariusc93 authored Sep 5, 2024
1 parent 5137e4e commit 3837e33
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ libp2p-dcutr = { version = "0.12.0", path = "protocols/dcutr" }
libp2p-dns = { version = "0.42.0", path = "transports/dns" }
libp2p-floodsub = { version = "0.45.0", path = "protocols/floodsub" }
libp2p-gossipsub = { version = "0.47.1", path = "protocols/gossipsub" }
libp2p-identify = { version = "0.45.0", path = "protocols/identify" }
libp2p-identify = { version = "0.45.1", path = "protocols/identify" }
libp2p-identity = { version = "0.2.9" }
libp2p-kad = { version = "0.47.0", path = "protocols/kad" }
libp2p-mdns = { version = "0.46.0", path = "protocols/mdns" }
Expand Down
5 changes: 5 additions & 0 deletions protocols/identify/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.45.1

- Add `hide_listen_addrs` option to prevent leaking (local) listen addresses.
See [PR 5507](https://github.com/libp2p/rust-libp2p/pull/5507).

## 0.45.0

- Address translation is moved here from `libp2p-core`.
Expand Down
2 changes: 1 addition & 1 deletion protocols/identify/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "libp2p-identify"
edition = "2021"
rust-version = { workspace = true }
description = "Nodes identification protocol for libp2p"
version = "0.45.0"
version = "0.45.1"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
Expand Down
23 changes: 18 additions & 5 deletions protocols/identify/src/behaviour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ pub struct Config {
///
/// Disabled by default.
pub cache_size: usize,

/// Whether to include our listen addresses in our responses. If enabled,
/// we will effectively only share our external addresses.
///
/// Disabled by default.
pub hide_listen_addrs: bool,
}

impl Config {
Expand All @@ -160,6 +166,7 @@ impl Config {
interval: Duration::from_secs(5 * 60),
push_listen_addr_updates: false,
cache_size: 100,
hide_listen_addrs: false,
}
}

Expand Down Expand Up @@ -189,6 +196,12 @@ impl Config {
self.cache_size = cache_size;
self
}

/// Configures whether we prevent sending out our listen addresses.
pub fn with_hide_listen_addrs(mut self, b: bool) -> Self {
self.hide_listen_addrs = b;
self
}
}

impl Behaviour {
Expand Down Expand Up @@ -258,11 +271,11 @@ impl Behaviour {
}

fn all_addresses(&self) -> HashSet<Multiaddr> {
self.listen_addresses
.iter()
.chain(self.external_addresses.iter())
.cloned()
.collect()
let mut addrs = HashSet::from_iter(self.external_addresses.iter().cloned());
if !self.config.hide_listen_addrs {
addrs.extend(self.listen_addresses.iter().cloned());
};
addrs
}

fn emit_new_external_addr_candidate_event(
Expand Down
71 changes: 71 additions & 0 deletions protocols/identify/tests/smoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,77 @@ async fn emits_unique_listen_addresses() {
assert!(reported_addrs.contains(&(swarm2_peer_id, swarm2_tcp_listen_addr)));
}

#[async_std::test]
async fn hides_listen_addresses() {
let _ = tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.try_init();

let mut swarm1 = Swarm::new_ephemeral(|identity| {
identify::Behaviour::new(
identify::Config::new("a".to_string(), identity.public())
.with_agent_version("b".to_string())
.with_interval(Duration::from_secs(1))
.with_cache_size(10),
)
});
let mut swarm2 = Swarm::new_ephemeral(|identity| {
identify::Behaviour::new(
identify::Config::new("c".to_string(), identity.public())
.with_agent_version("d".to_string())
.with_hide_listen_addrs(true),
)
});

let (_swarm2_mem_listen_addr, swarm2_tcp_listen_addr) =
swarm2.listen().with_tcp_addr_external().await;
let swarm2_peer_id = *swarm2.local_peer_id();
swarm1.connect(&mut swarm2).await;

async_std::task::spawn(swarm2.loop_on_next());

let swarm_events = futures::stream::poll_fn(|cx| swarm1.poll_next_unpin(cx))
.take(8)
.collect::<Vec<_>>()
.await;

let infos = swarm_events
.iter()
.filter_map(|e| match e {
SwarmEvent::Behaviour(identify::Event::Received { info, .. }) => Some(info.clone()),
_ => None,
})
.collect::<Vec<_>>();

assert!(
infos.len() > 1,
"should exchange identify payload more than once"
);

let listen_addrs = infos
.iter()
.map(|i| i.listen_addrs.clone())
.collect::<Vec<_>>();

for addrs in listen_addrs {
assert_eq!(addrs.len(), 1);
assert!(addrs.contains(&swarm2_tcp_listen_addr));
}

let reported_addrs = swarm_events
.iter()
.filter_map(|e| match e {
SwarmEvent::NewExternalAddrOfPeer { peer_id, address } => {
Some((*peer_id, address.clone()))
}
_ => None,
})
.collect::<Vec<_>>();

assert_eq!(reported_addrs.len(), 1, "To have one TCP address of remote");
assert!(reported_addrs.contains(&(swarm2_peer_id, swarm2_tcp_listen_addr)));
}

#[async_std::test]
async fn identify_push() {
let _ = tracing_subscriber::fmt()
Expand Down

0 comments on commit 3837e33

Please sign in to comment.