diff options
Diffstat (limited to 'src/transport/libp2p/book.rs')
| -rw-r--r-- | src/transport/libp2p/book.rs | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/src/transport/libp2p/book.rs b/src/transport/libp2p/book.rs index f466aef..b2ce7bb 100644 --- a/src/transport/libp2p/book.rs +++ b/src/transport/libp2p/book.rs @@ -53,6 +53,9 @@ pub(super) struct Book { pub(super) ignored: Vec<IpRange>, /// `Libp2pConfig::prefer`: addresses there first (`preference`). pub(super) preferred: Vec<IpRange>, + /// Which address ranges have a route from here (`routes`): those without are left + /// out, as if ignored. + pub(super) routes: Routes, /// `Libp2pConfig::relay`: this node relays, and says so. pub(super) serving: bool, /// Relays named to pick (configured, listed), by peer: picked first. @@ -275,7 +278,10 @@ impl Book { direct.retain(|address| !first.contains(address)); direct.sort_by_key(|address| self.preferred_range(address)); first.extend(direct); - first.retain(|address| !ignored(&self.ignored, address)); + first.retain(|address| { + !ignored(&self.ignored, address) + && ip_of(address).is_none_or(|ip| self.routes.publishable(ip)) + }); first } } @@ -464,7 +470,7 @@ impl Book { if !self.addresses.contains_key(&peer) && self.addresses.len() >= MAX_PEERS { return; } - if left_out(&self.ignored, &address) { + if self.left_out(&address) { return; } if self @@ -481,6 +487,38 @@ impl Book { addresses.truncate(ADDRESSES_PER_PEER); } + /// Whether `address` can only be reached over a range left out: ignored + /// (`left_out`), or without a route from here (`routes`), directly or through a + /// relay there. + pub(super) fn left_out(&mut self, address: &Multiaddr) -> bool { + if left_out(&self.ignored, address) { + return true; + } + let at = if is_relayed(address) { + address + .iter() + .take_while(|protocol| !matches!(protocol, Protocol::P2pCircuit)) + .collect::<Multiaddr>() + } else { + address.clone() + }; + ip_of(&at).is_some_and(|ip| !self.routes.routable(ip)) + } + + /// Asks again which ranges have a route (`Routes::recheck`); the addresses in those + /// that lost theirs go. + pub(super) fn recheck_routes(&mut self) { + let lost = self.routes.recheck(); + if lost.is_empty() { + return; + } + for known in self.addresses.values_mut() { + known.retain(|address| { + ip_of(address).is_none_or(|ip| !lost.iter().any(|range| range.contains(ip))) + }); + } + } + /// The addresses `explore` dials `peer` at, noted as dialled: a node of the swarm /// connected directly, at addresses of its not dialled so yet, and with `again` /// not only those at an IP it isn't connected at (an inbound connection's remote @@ -506,10 +544,17 @@ impl Book { .filter(|address| is_ip(address) && !left_out(&self.ignored, address)) .filter(|address| again || !used.contains(&ip_of(address))) .filter(|address| !tried.contains(*address)) - .take(EXPLORED_AT_ONCE) .cloned() .collect(); - tried.extend(candidates.iter().cloned()); + let candidates: Vec<Multiaddr> = candidates + .into_iter() + .filter(|address| !self.left_out(address)) + .take(EXPLORED_AT_ONCE) + .collect(); + self.explored + .entry(peer) + .or_default() + .extend(candidates.iter().cloned()); candidates } @@ -567,7 +612,7 @@ pub(super) fn ip_of(address: &Multiaddr) -> Option<std::net::IpAddr> { } /// Whether `ip` can be reached from the internet, as far as its range tells. -fn is_public(ip: std::net::IpAddr) -> bool { +pub(super) fn is_public(ip: std::net::IpAddr) -> bool { use std::net::IpAddr; match ip { IpAddr::V4(ip) => { |
