summaryrefslogtreecommitdiffstats
path: root/src/transport/p2p.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/p2p.rs')
-rw-r--r--src/transport/p2p.rs45
1 files changed, 44 insertions, 1 deletions
diff --git a/src/transport/p2p.rs b/src/transport/p2p.rs
index 5829419..3fa0bef 100644
--- a/src/transport/p2p.rs
+++ b/src/transport/p2p.rs
@@ -270,6 +270,30 @@ fn is_relayed(address: &Multiaddr) -> bool {
.any(|protocol| matches!(protocol, Protocol::P2pCircuit))
}
+/// The relay `address` goes through, if it goes through one: the peer before
+/// `/p2p-circuit`.
+fn relay_of(address: &Multiaddr) -> Option<PeerId> {
+ let mut relay = None;
+ for protocol in address.iter() {
+ match protocol {
+ Protocol::P2p(peer) => relay = Some(peer),
+ Protocol::P2pCircuit => return relay,
+ _ => {}
+ }
+ }
+ None
+}
+
+/// The addresses of `known` this node can dial: not those through itself as the relay
+/// (a relay reaches the nodes it relays for only while they are connected to it).
+fn dialable(known: &[Multiaddr], local: PeerId) -> Vec<Multiaddr> {
+ known
+ .iter()
+ .filter(|address| relay_of(address) != Some(local))
+ .cloned()
+ .collect()
+}
+
/// `address` with the peer ID it ends in, if it ends in one.
fn split_peer(address: &Multiaddr) -> Option<PeerId> {
match address.iter().last() {
@@ -359,7 +383,7 @@ impl Libp2pTransport {
let addresses = lock(&self.book)
.addresses
.get(&peer)
- .cloned()
+ .map(|known| dialable(known, self.peer_id))
.unwrap_or_default();
let (done, connected) = oneshot::channel();
self.commands
@@ -1441,6 +1465,25 @@ mod tests {
assert_eq!(book.discovered, [address.with_p2p(lan).unwrap()]);
}
+ /// A relay doesn't dial the nodes it relays for through itself.
+ #[test]
+ fn no_circuits_through_ourselves() {
+ let (us, other_relay, target) = (peer(), peer(), peer());
+ let through = |relay: PeerId| -> Multiaddr {
+ format!("/ip6/fd00::1/tcp/9661/p2p/{relay}/p2p-circuit")
+ .parse()
+ .unwrap()
+ };
+ let direct: Multiaddr = "/ip6/fd00::2/tcp/9661".parse().unwrap();
+ assert_eq!(relay_of(&through(us)), Some(us));
+ assert_eq!(relay_of(&direct), None);
+ assert_eq!(relay_of(&direct.clone().with_p2p(target).unwrap()), None);
+ assert_eq!(
+ dialable(&[through(us), through(other_relay), direct.clone()], us),
+ [through(other_relay), direct]
+ );
+ }
+
#[tokio::test]
async fn unknown_peers_are_refused() {
let (b, _) = memory_node();