diff options
Diffstat (limited to 'src/transport/p2p.rs')
| -rw-r--r-- | src/transport/p2p.rs | 45 |
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(); |
