|
@@ -16,23 +16,18 @@
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-use std::{
|
|
|
|
|
- collections::{HashMap, HashSet},
|
|
|
|
|
- sync::Arc,
|
|
|
|
|
- time::SystemTime,
|
|
|
|
|
-};
|
|
|
|
|
|
|
+use std::{collections::HashSet, sync::Arc};
|
|
|
|
|
|
|
|
use log::{debug, trace};
|
|
use log::{debug, trace};
|
|
|
use rand::{
|
|
use rand::{
|
|
|
prelude::{IteratorRandom, SliceRandom},
|
|
prelude::{IteratorRandom, SliceRandom},
|
|
|
rngs::OsRng,
|
|
rngs::OsRng,
|
|
|
- Rng,
|
|
|
|
|
};
|
|
};
|
|
|
-use smol::{lock::RwLock, Executor};
|
|
|
|
|
|
|
+use smol::lock::RwLock;
|
|
|
use url::Url;
|
|
use url::Url;
|
|
|
|
|
|
|
|
use super::{
|
|
use super::{
|
|
|
- connector::Connector, p2p::P2pPtr, protocol::ProtocolVersion, session::Session,
|
|
|
|
|
|
|
+ p2p::P2pPtr,
|
|
|
settings::SettingsPtr,
|
|
settings::SettingsPtr,
|
|
|
};
|
|
};
|
|
|
use crate::{
|
|
use crate::{
|
|
@@ -55,15 +50,6 @@ pub struct Hosts {
|
|
|
// Recently seen nodes.
|
|
// Recently seen nodes.
|
|
|
pub whitelist: RwLock<Vec<(Url, u64)>>,
|
|
pub whitelist: RwLock<Vec<(Url, u64)>>,
|
|
|
|
|
|
|
|
- ///// Set of stored addresses
|
|
|
|
|
- //addrs: RwLock<HashSet<Url>>,
|
|
|
|
|
- /// Set of stored addresses that are quarantined.
|
|
|
|
|
- /// We quarantine peers we've been unable to connect to, but we keep them
|
|
|
|
|
- /// around so we can potentially try them again, up to n tries. This should
|
|
|
|
|
- /// be helpful in order to self-heal the p2p connections in case we have an
|
|
|
|
|
- /// Internet interrupt (goblins unplugging cables)
|
|
|
|
|
- quarantine: RwLock<HashMap<Url, usize>>,
|
|
|
|
|
-
|
|
|
|
|
/// Peers we reject from connecting
|
|
/// Peers we reject from connecting
|
|
|
rejected: RwLock<HashSet<String>>,
|
|
rejected: RwLock<HashSet<String>>,
|
|
|
|
|
|
|
@@ -80,34 +66,17 @@ impl Hosts {
|
|
|
Arc::new(Self {
|
|
Arc::new(Self {
|
|
|
whitelist: RwLock::new(Vec::new()),
|
|
whitelist: RwLock::new(Vec::new()),
|
|
|
greylist: RwLock::new(Vec::new()),
|
|
greylist: RwLock::new(Vec::new()),
|
|
|
- //addrs: RwLock::new(HashSet::new()),
|
|
|
|
|
- quarantine: RwLock::new(HashMap::new()),
|
|
|
|
|
rejected: RwLock::new(HashSet::new()),
|
|
rejected: RwLock::new(HashSet::new()),
|
|
|
store_subscriber: Subscriber::new(),
|
|
store_subscriber: Subscriber::new(),
|
|
|
settings,
|
|
settings,
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ///// Append given addrs to the known set.
|
|
|
|
|
- //pub async fn store(&self, addrs: &[Url]) {
|
|
|
|
|
- // debug!(target: "net::hosts::store()", "hosts::store() [START]");
|
|
|
|
|
-
|
|
|
|
|
- // let filtered_addrs = self.filter_addresses(addrs).await;
|
|
|
|
|
- // let filtered_addrs_len = filtered_addrs.len();
|
|
|
|
|
-
|
|
|
|
|
- // if !filtered_addrs.is_empty() {
|
|
|
|
|
- // let mut addrs_map = self.addrs.write().await;
|
|
|
|
|
- // for addr in filtered_addrs {
|
|
|
|
|
- // debug!(target: "net::hosts::store()", "Inserting {}", addr);
|
|
|
|
|
- // addrs_map.insert(addr);
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // self.store_subscriber.notify(filtered_addrs_len).await;
|
|
|
|
|
- // debug!(target: "net::hosts::store()", "hosts::store() [END]");
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
- // Gets addresses from the whitelist.
|
|
|
|
|
|
|
+ /// Loops through whitelist addresses to find an outbound address that we can
|
|
|
|
|
+ /// connect to. Check whether the address is valid by making sure it isn't
|
|
|
|
|
+ /// our own inbound address, then checks whether it is already connected
|
|
|
|
|
+ /// (exists) or connecting (pending).
|
|
|
|
|
+ /// Lastly adds matching address to the pending list.
|
|
|
pub async fn whitelist_fetch_address_with_lock(
|
|
pub async fn whitelist_fetch_address_with_lock(
|
|
|
&self,
|
|
&self,
|
|
|
p2p: P2pPtr,
|
|
p2p: P2pPtr,
|
|
@@ -212,7 +181,7 @@ impl Hosts {
|
|
|
pub async fn greylist_store(&self, addrs: &[(Url, u64)]) {
|
|
pub async fn greylist_store(&self, addrs: &[(Url, u64)]) {
|
|
|
debug!(target: "net::hosts::greylist_store()", "hosts::greylist_store() [START]");
|
|
debug!(target: "net::hosts::greylist_store()", "hosts::greylist_store() [START]");
|
|
|
|
|
|
|
|
- let filtered_addrs = self.filter_addresses2(addrs).await;
|
|
|
|
|
|
|
+ let filtered_addrs = self.filter_addresses(addrs).await;
|
|
|
let filtered_addrs_len = filtered_addrs.len();
|
|
let filtered_addrs_len = filtered_addrs.len();
|
|
|
|
|
|
|
|
if !filtered_addrs.is_empty() {
|
|
if !filtered_addrs.is_empty() {
|
|
@@ -268,13 +237,11 @@ impl Hosts {
|
|
|
|
|
|
|
|
pub async fn whitelist_downgrade(&self, addr: &Url) {
|
|
pub async fn whitelist_downgrade(&self, addr: &Url) {
|
|
|
// First lookup the entry using its addr.
|
|
// First lookup the entry using its addr.
|
|
|
- let mut index = 0;
|
|
|
|
|
let mut entry = vec![];
|
|
let mut entry = vec![];
|
|
|
|
|
|
|
|
let whitelist = self.whitelist.read().await;
|
|
let whitelist = self.whitelist.read().await;
|
|
|
- for (i, (url, time)) in whitelist.iter().enumerate() {
|
|
|
|
|
|
|
+ for (url, time) in whitelist.iter() {
|
|
|
if url == addr {
|
|
if url == addr {
|
|
|
- index = i;
|
|
|
|
|
entry.push((url.clone(), time.clone()));
|
|
entry.push((url.clone(), time.clone()));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -284,6 +251,7 @@ impl Hosts {
|
|
|
|
|
|
|
|
// Remove this item from the whitelist.
|
|
// Remove this item from the whitelist.
|
|
|
let mut whitelist = self.whitelist.write().await;
|
|
let mut whitelist = self.whitelist.write().await;
|
|
|
|
|
+ // TODO: test!
|
|
|
let index = whitelist.iter().position(|x| *x == entry[0]);
|
|
let index = whitelist.iter().position(|x| *x == entry[0]);
|
|
|
// This should never fail since the entry exists.
|
|
// This should never fail since the entry exists.
|
|
|
whitelist.remove(index.unwrap());
|
|
whitelist.remove(index.unwrap());
|
|
@@ -335,77 +303,7 @@ impl Hosts {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// Filter given addresses based on certain rulesets and validity.
|
|
/// Filter given addresses based on certain rulesets and validity.
|
|
|
- async fn filter_addresses(&self, addrs: &[Url]) -> Vec<Url> {
|
|
|
|
|
- debug!(target: "net::hosts::filter_addresses()", "Filtering addrs: {:?}", addrs);
|
|
|
|
|
- let mut ret = vec![];
|
|
|
|
|
- let localnet = self.settings.localnet;
|
|
|
|
|
-
|
|
|
|
|
- 'addr_loop: for addr_ in addrs {
|
|
|
|
|
- // Validate that the format is `scheme://host_str:port`
|
|
|
|
|
- if addr_.host_str().is_none() ||
|
|
|
|
|
- addr_.port().is_none() ||
|
|
|
|
|
- addr_.cannot_be_a_base() ||
|
|
|
|
|
- addr_.path_segments().is_some()
|
|
|
|
|
- {
|
|
|
|
|
- continue
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if self.is_rejected(addr_).await {
|
|
|
|
|
- debug!(target: "net::hosts::filter_addresses()", "Peer {} is rejected", addr_);
|
|
|
|
|
- continue
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- let host_str = addr_.host_str().unwrap();
|
|
|
|
|
-
|
|
|
|
|
- if !localnet {
|
|
|
|
|
- // Our own external addresses should never enter the hosts set.
|
|
|
|
|
- for ext in &self.settings.external_addrs {
|
|
|
|
|
- if host_str == ext.host_str().unwrap() {
|
|
|
|
|
- continue 'addr_loop
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // We do this hack in order to parse IPs properly.
|
|
|
|
|
- // https://github.com/whatwg/url/issues/749
|
|
|
|
|
- let addr = Url::parse(&addr_.as_str().replace(addr_.scheme(), "http")).unwrap();
|
|
|
|
|
-
|
|
|
|
|
- // Filter non-global ranges if we're not allowing localnet.
|
|
|
|
|
- // Should never be allowed in production, so we don't really care
|
|
|
|
|
- // about some of them (e.g. 0.0.0.0, or broadcast, etc.).
|
|
|
|
|
- if !localnet && self.is_local_host(addr).await {
|
|
|
|
|
- continue
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- match addr_.scheme() {
|
|
|
|
|
- // Validate that the address is an actual onion.
|
|
|
|
|
- #[cfg(feature = "p2p-tor")]
|
|
|
|
|
- "tor" | "tor+tls" => {
|
|
|
|
|
- use std::str::FromStr;
|
|
|
|
|
- if tor_hscrypto::pk::HsId::from_str(host_str).is_err() {
|
|
|
|
|
- continue
|
|
|
|
|
- }
|
|
|
|
|
- debug!(target: "net::hosts::filter_addresses()", "[Tor] Valid: {}", host_str);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- #[cfg(feature = "p2p-nym")]
|
|
|
|
|
- "nym" | "nym+tls" => continue, // <-- Temp skip
|
|
|
|
|
-
|
|
|
|
|
- #[cfg(feature = "p2p-tcp")]
|
|
|
|
|
- "tcp" | "tcp+tls" => {
|
|
|
|
|
- debug!(target: "net::hosts::filter_addresses()", "[TCP] Valid: {}", host_str);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _ => continue,
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- ret.push(addr_.clone());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- ret
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- async fn filter_addresses2(&self, addrs: &[(Url, u64)]) -> Vec<(Url, u64)> {
|
|
|
|
|
|
|
+ async fn filter_addresses(&self, addrs: &[(Url, u64)]) -> Vec<(Url, u64)> {
|
|
|
debug!(target: "net::hosts::filter_addresses()", "Filtering addrs: {:?}", addrs);
|
|
debug!(target: "net::hosts::filter_addresses()", "Filtering addrs: {:?}", addrs);
|
|
|
let mut ret = vec![];
|
|
let mut ret = vec![];
|
|
|
let localnet = self.settings.localnet;
|
|
let localnet = self.settings.localnet;
|
|
@@ -474,144 +372,6 @@ impl Hosts {
|
|
|
|
|
|
|
|
ret
|
|
ret
|
|
|
}
|
|
}
|
|
|
- //// Probe random peers on the greylist. If a peer is responsive, update the last_seen field and
|
|
|
|
|
- //// add it to the whitelist. If a node does not respond, remove it from the greylist.
|
|
|
|
|
- //// Called periodically.
|
|
|
|
|
- //pub async fn refresh_greylist(&self, p2p: P2pPtr, ex: Arc<Executor<'_>>) {
|
|
|
|
|
- // let mut greylist = self.greylist.write().await;
|
|
|
|
|
- // let mut whitelist = self.whitelist.write().await;
|
|
|
|
|
-
|
|
|
|
|
- // // Randomly select an entry from the greylist.
|
|
|
|
|
- // let position = rand::thread_rng().gen_range(0..greylist.len());
|
|
|
|
|
- // let entry = &greylist[position];
|
|
|
|
|
- // let url = &entry.0;
|
|
|
|
|
-
|
|
|
|
|
- // // Probe node to see if it's active.
|
|
|
|
|
- // let online: bool = self.probe_node(url, p2p.clone(), ex.clone()).await;
|
|
|
|
|
-
|
|
|
|
|
- // if online {
|
|
|
|
|
- // // Peer is responsive. Update last_seen and add it to the whitelist.
|
|
|
|
|
- // let last_seen =
|
|
|
|
|
- // SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
|
|
|
|
|
-
|
|
|
|
|
- // // Remove oldest element if the whitelist reaches max size.
|
|
|
|
|
- // if whitelist.len() == 1000 {
|
|
|
|
|
- // // Last element in vector should have the oldest timestamp.
|
|
|
|
|
- // // This should never crash as only returns None when whitelist len() == 0.
|
|
|
|
|
- // let entry = whitelist.pop().unwrap();
|
|
|
|
|
- // debug!(target: "net::hosts::refresh_greylist()", "Whitelist reached max size. Removed host {}", entry.0);
|
|
|
|
|
- // }
|
|
|
|
|
- // // Append to the whitelist.
|
|
|
|
|
- // debug!(target: "net::hosts::refresh_greylist()", "Adding peer {} to whitelist", url);
|
|
|
|
|
- // whitelist.push((url.clone(), last_seen));
|
|
|
|
|
-
|
|
|
|
|
- // // Sort whitelist by last_seen.
|
|
|
|
|
- // whitelist.sort_unstable_by_key(|entry| entry.1);
|
|
|
|
|
-
|
|
|
|
|
- // // Remove whitelisted peer from the greylist.
|
|
|
|
|
- // debug!(target: "net::hosts::refresh_greylist()", "Removing whitelisted peer {} from greylist", url);
|
|
|
|
|
- // greylist.remove(position);
|
|
|
|
|
- // } else {
|
|
|
|
|
- // // Peer is not responsive. Remove it from the greylist.
|
|
|
|
|
- // debug!(target: "net::hosts::refresh_greylist()", "Peer {} is not response. Removing from greylist", url);
|
|
|
|
|
- // greylist.remove(position);
|
|
|
|
|
- // }
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
- //pub async fn refresh_whitelist(&self, url: &Url, p2p: P2pPtr, ex: Arc<Executor<'_>>) {
|
|
|
|
|
- // let mut whitelist = self.whitelist.write().await;
|
|
|
|
|
-
|
|
|
|
|
- // // Probe node to see if it's active.
|
|
|
|
|
- // let online: bool = self.probe_node(url, p2p.clone(), ex.clone()).await;
|
|
|
|
|
-
|
|
|
|
|
- // if online {
|
|
|
|
|
- // // Peer is responsive. Update last_seen and add it to the whitelist.
|
|
|
|
|
- // let last_seen =
|
|
|
|
|
- // SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
|
|
|
|
|
-
|
|
|
|
|
- // // Remove oldest element if the whitelist reaches max size.
|
|
|
|
|
- // if whitelist.len() == 1000 {
|
|
|
|
|
- // // Last element in vector should have the oldest timestamp.
|
|
|
|
|
- // // This should never crash as only returns None when whitelist len() == 0.
|
|
|
|
|
- // let entry = whitelist.pop().unwrap();
|
|
|
|
|
- // debug!(target: "net::hosts::refresh_whitelist()", "Whitelist reached max size. Removed host {}", entry.0);
|
|
|
|
|
- // }
|
|
|
|
|
- // // Append to the whitelist.
|
|
|
|
|
- // debug!(target: "net::hosts::refresh_whitelist()", "Adding peer {} to whitelist", url);
|
|
|
|
|
- // whitelist.push((url.clone(), last_seen));
|
|
|
|
|
-
|
|
|
|
|
- // // Sort whitelist by last_seen.
|
|
|
|
|
- // whitelist.sort_unstable_by_key(|entry| entry.1);
|
|
|
|
|
- // }
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
- //pub async fn probe_node(&self, host: &Url, p2p: P2pPtr, ex: Arc<Executor<'_>>) -> bool {
|
|
|
|
|
- // let p2p_ = p2p.clone();
|
|
|
|
|
- // let ex_ = ex.clone();
|
|
|
|
|
- // let session_out = p2p_.session_outbound();
|
|
|
|
|
- // let session_weak = Arc::downgrade(&session_out);
|
|
|
|
|
-
|
|
|
|
|
- // let connector = Connector::new(self.settings.clone(), session_weak);
|
|
|
|
|
- // debug!(target: "net::hosts::probe_node()", "Connecting to {}", host);
|
|
|
|
|
- // match connector.connect(host).await {
|
|
|
|
|
- // Ok((_url, channel)) => {
|
|
|
|
|
- // debug!(target: "net::hosts::probe_node()", "Connected successfully!");
|
|
|
|
|
- // let proto_ver = ProtocolVersion::new(channel.clone(), self.settings.clone()).await;
|
|
|
|
|
-
|
|
|
|
|
- // let handshake_task = session_out.perform_handshake_protocols(
|
|
|
|
|
- // proto_ver,
|
|
|
|
|
- // channel.clone(),
|
|
|
|
|
- // ex_.clone(),
|
|
|
|
|
- // );
|
|
|
|
|
-
|
|
|
|
|
- // channel.clone().start(ex_.clone());
|
|
|
|
|
-
|
|
|
|
|
- // match handshake_task.await {
|
|
|
|
|
- // Ok(()) => {
|
|
|
|
|
- // debug!(target: "net::hosts::probe_node()", "Handshake success! Stopping channel.");
|
|
|
|
|
- // channel.stop().await;
|
|
|
|
|
- // return true
|
|
|
|
|
- // }
|
|
|
|
|
- // Err(e) => {
|
|
|
|
|
- // debug!(target: "net::hosts::probe_node()", "Handshake failure! {}", e);
|
|
|
|
|
- // return false
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // Err(e) => {
|
|
|
|
|
- // debug!(target: "net::hosts::probe_node()", "Failed to connect to {}, ({})", host, e);
|
|
|
|
|
- // return false
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- //}
|
|
|
|
|
- //pub async fn remove(&self, url: &Url) {
|
|
|
|
|
- // debug!(target: "net::hosts::remove()", "Removing peer {}", url);
|
|
|
|
|
- // self.addrs.write().await.remove(url);
|
|
|
|
|
- // self.quarantine.write().await.remove(url);
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
- ///// Quarantine a peer.
|
|
|
|
|
- ///// If they've been quarantined for more than a configured limit, forget them.
|
|
|
|
|
- //pub async fn quarantine(&self, url: &Url) {
|
|
|
|
|
- // debug!(target: "net::hosts::remove()", "Quarantining peer {}", url);
|
|
|
|
|
- // // Remove from main hosts set
|
|
|
|
|
- // self.addrs.write().await.remove(url);
|
|
|
|
|
-
|
|
|
|
|
- // let mut q = self.quarantine.write().await;
|
|
|
|
|
- // if let Some(retries) = q.get_mut(url) {
|
|
|
|
|
- // *retries += 1;
|
|
|
|
|
- // debug!(target: "net::hosts::quarantine()", "Peer {} quarantined {} times", url, retries);
|
|
|
|
|
- // if *retries == self.settings.hosts_quarantine_limit {
|
|
|
|
|
- // debug!(target: "net::hosts::quarantine()", "Banning peer {}", url);
|
|
|
|
|
- // q.remove(url);
|
|
|
|
|
- // self.mark_rejected(url).await;
|
|
|
|
|
- // }
|
|
|
|
|
- // } else {
|
|
|
|
|
- // debug!(target: "net::hosts::remove()", "Added peer {} to quarantine", url);
|
|
|
|
|
- // q.insert(url.clone(), 0);
|
|
|
|
|
- // }
|
|
|
|
|
- //}
|
|
|
|
|
|
|
|
|
|
/// Check if a given peer (URL) is in the set of rejected hosts
|
|
/// Check if a given peer (URL) is in the set of rejected hosts
|
|
|
pub async fn is_rejected(&self, peer: &Url) -> bool {
|
|
pub async fn is_rejected(&self, peer: &Url) -> bool {
|
|
@@ -648,22 +408,17 @@ impl Hosts {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ///// Check if the host list is empty.
|
|
|
|
|
- //pub async fn is_empty(&self) -> bool {
|
|
|
|
|
- // self.addrs.read().await.is_empty()
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
- // Check if the greylist is empty.
|
|
|
|
|
|
|
+ /// Check if the greylist is empty.
|
|
|
pub async fn is_empty_greylist(&self) -> bool {
|
|
pub async fn is_empty_greylist(&self) -> bool {
|
|
|
self.greylist.read().await.is_empty()
|
|
self.greylist.read().await.is_empty()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Check if the whitelist is empty.
|
|
|
|
|
|
|
+ /// Check if the whitelist is empty.
|
|
|
pub async fn is_empty_whitelist(&self) -> bool {
|
|
pub async fn is_empty_whitelist(&self) -> bool {
|
|
|
self.whitelist.read().await.is_empty()
|
|
self.whitelist.read().await.is_empty()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Check if host is in the greylist
|
|
|
|
|
|
|
+ /// Check if host is in the greylist
|
|
|
pub async fn greylist_contains(&self, addr: &Url) -> bool {
|
|
pub async fn greylist_contains(&self, addr: &Url) -> bool {
|
|
|
let greylist = self.greylist.read().await;
|
|
let greylist = self.greylist.read().await;
|
|
|
if greylist.iter().any(|(u, _t)| u == addr) {
|
|
if greylist.iter().any(|(u, _t)| u == addr) {
|
|
@@ -672,7 +427,7 @@ impl Hosts {
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Check if host is in the whitelist
|
|
|
|
|
|
|
+ /// Check if host is in the whitelist
|
|
|
pub async fn whitelist_contains(&self, addr: &Url) -> bool {
|
|
pub async fn whitelist_contains(&self, addr: &Url) -> bool {
|
|
|
let whitelist = self.whitelist.read().await;
|
|
let whitelist = self.whitelist.read().await;
|
|
|
if whitelist.iter().any(|(u, _t)| u == addr) {
|
|
if whitelist.iter().any(|(u, _t)| u == addr) {
|
|
@@ -681,7 +436,7 @@ impl Hosts {
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Get the index for a given addr on the whitelist.
|
|
|
|
|
|
|
+ /// Get the index for a given addr on the whitelist.
|
|
|
pub async fn get_whitelist_index_at_addr(&self, addr: &Url) -> usize {
|
|
pub async fn get_whitelist_index_at_addr(&self, addr: &Url) -> usize {
|
|
|
let whitelist = self.whitelist.read().await;
|
|
let whitelist = self.whitelist.read().await;
|
|
|
for (i, (url, _time)) in whitelist.iter().enumerate() {
|
|
for (i, (url, _time)) in whitelist.iter().enumerate() {
|
|
@@ -693,50 +448,23 @@ impl Hosts {
|
|
|
return 0
|
|
return 0
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ///// Check if host is already in the set
|
|
|
|
|
- //pub async fn contains(&self, addr: &Url) -> bool {
|
|
|
|
|
- // self.addrs.read().await.contains(addr)
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
- ///// Return all known hosts
|
|
|
|
|
- //pub async fn fetch_all(&self) -> Vec<Url> {
|
|
|
|
|
- // self.addrs.read().await.iter().cloned().collect()
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
/// Return all known whitelisted hosts
|
|
/// Return all known whitelisted hosts
|
|
|
pub async fn whitelist_fetch_all(&self) -> Vec<(Url, u64)> {
|
|
pub async fn whitelist_fetch_all(&self) -> Vec<(Url, u64)> {
|
|
|
self.whitelist.read().await.iter().cloned().collect()
|
|
self.whitelist.read().await.iter().cloned().collect()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ///// Get up to n random peers from the hosts set.
|
|
|
|
|
- //pub async fn fetch_n_random(&self, n: u32) -> Vec<Url> {
|
|
|
|
|
- // let n = n as usize;
|
|
|
|
|
- // if n == 0 {
|
|
|
|
|
- // return vec![]
|
|
|
|
|
- // }
|
|
|
|
|
- // let addrs = self.addrs.read().await;
|
|
|
|
|
- // let urls = addrs.iter().choose_multiple(&mut OsRng, n.min(addrs.len()));
|
|
|
|
|
- // urls.iter().map(|&url| url.clone()).collect()
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
- ///// Get up to n random peers that match the given transport schemes from the hosts set.
|
|
|
|
|
- //pub async fn fetch_n_random_with_schemes(&self, schemes: &[String], n: u32) -> Vec<Url> {
|
|
|
|
|
- // let n = n as usize;
|
|
|
|
|
- // if n == 0 {
|
|
|
|
|
- // return vec![]
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // // Retrieve all peers corresponding to that transport schemes
|
|
|
|
|
- // let hosts = self.fetch_with_schemes(schemes, None).await;
|
|
|
|
|
- // if hosts.is_empty() {
|
|
|
|
|
- // return hosts
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // // Grab random ones
|
|
|
|
|
- // let urls = hosts.iter().choose_multiple(&mut OsRng, n.min(hosts.len()));
|
|
|
|
|
- // urls.iter().map(|&url| url.clone()).collect()
|
|
|
|
|
- //}
|
|
|
|
|
|
|
+ /// Get up to n random peers from the whitelist.
|
|
|
|
|
+ pub async fn fetch_n_random(&self, n: u32) -> Vec<(Url, u64)> {
|
|
|
|
|
+ let n = n as usize;
|
|
|
|
|
+ if n == 0 {
|
|
|
|
|
+ return vec![]
|
|
|
|
|
+ }
|
|
|
|
|
+ let addrs = self.whitelist.read().await;
|
|
|
|
|
+ let urls = addrs.iter().choose_multiple(&mut OsRng, n.min(addrs.len()));
|
|
|
|
|
+ urls.iter().map(|&url| url.clone()).collect()
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ /// Get up to n random whitelisted peers that match the given transport schemes from the hosts set.
|
|
|
pub async fn whitelist_fetch_n_random_with_schemes(
|
|
pub async fn whitelist_fetch_n_random_with_schemes(
|
|
|
&self,
|
|
&self,
|
|
|
schemes: &[String],
|
|
schemes: &[String],
|
|
@@ -758,24 +486,7 @@ impl Hosts {
|
|
|
urls.iter().map(|&url| url.clone()).collect()
|
|
urls.iter().map(|&url| url.clone()).collect()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ///// Get up to n random peers that don't match the given transport schemes from the hosts set.
|
|
|
|
|
- //pub async fn fetch_n_random_excluding_schemes(&self, schemes: &[String], n: u32) -> Vec<Url> {
|
|
|
|
|
- // let n = n as usize;
|
|
|
|
|
- // if n == 0 {
|
|
|
|
|
- // return vec![]
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // // Retrieve all peers not corresponding to that transport schemes
|
|
|
|
|
- // let hosts = self.fetch_exluding_schemes(schemes, None).await;
|
|
|
|
|
- // if hosts.is_empty() {
|
|
|
|
|
- // return hosts
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // // Grab random ones
|
|
|
|
|
- // let urls = hosts.iter().choose_multiple(&mut OsRng, n.min(hosts.len()));
|
|
|
|
|
- // urls.iter().map(|&url| url.clone()).collect()
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
|
|
+ /// Get up to n random whitelisted peers that don't match the given transport schemes from the hosts set.
|
|
|
pub async fn whitelist_fetch_n_random_excluding_schemes(
|
|
pub async fn whitelist_fetch_n_random_excluding_schemes(
|
|
|
&self,
|
|
&self,
|
|
|
schemes: &[String],
|
|
schemes: &[String],
|
|
@@ -797,46 +508,8 @@ impl Hosts {
|
|
|
urls.iter().map(|&url| url.clone()).collect()
|
|
urls.iter().map(|&url| url.clone()).collect()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ///// Get up to limit peers that match the given transport schemes from the hosts set.
|
|
|
|
|
- ///// If limit was not provided, return all matching peers.
|
|
|
|
|
- //pub async fn fetch_with_schemes(&self, schemes: &[String], limit: Option<usize>) -> Vec<Url> {
|
|
|
|
|
- // let addrs = self.addrs.read().await;
|
|
|
|
|
- // let mut limit = match limit {
|
|
|
|
|
- // Some(l) => l.min(addrs.len()),
|
|
|
|
|
- // None => addrs.len(),
|
|
|
|
|
- // };
|
|
|
|
|
- // let mut ret = vec![];
|
|
|
|
|
-
|
|
|
|
|
- // if limit == 0 {
|
|
|
|
|
- // return ret
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // for addr in addrs.iter() {
|
|
|
|
|
- // if schemes.contains(&addr.scheme().to_string()) {
|
|
|
|
|
- // ret.push(addr.clone());
|
|
|
|
|
- // limit -= 1;
|
|
|
|
|
- // if limit == 0 {
|
|
|
|
|
- // return ret
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // // If we didn't find any, pick some from the quarantine zone
|
|
|
|
|
- // if ret.is_empty() {
|
|
|
|
|
- // for addr in self.quarantine.read().await.keys() {
|
|
|
|
|
- // if schemes.contains(&addr.scheme().to_string()) {
|
|
|
|
|
- // ret.push(addr.clone());
|
|
|
|
|
- // limit -= 1;
|
|
|
|
|
- // if limit == 0 {
|
|
|
|
|
- // break
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // ret
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
|
|
+ /// Get up to limit peers that match the given transport schemes from the whitelist.
|
|
|
|
|
+ /// If limit was not provided, return all matching peers.
|
|
|
pub async fn whitelist_fetch_with_schemes(
|
|
pub async fn whitelist_fetch_with_schemes(
|
|
|
&self,
|
|
&self,
|
|
|
schemes: &[String],
|
|
schemes: &[String],
|
|
@@ -879,50 +552,8 @@ impl Hosts {
|
|
|
ret
|
|
ret
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ///// Get up to limit peers that don't match the given transport schemes from the hosts set.
|
|
|
|
|
- ///// If limit was not provided, return all matching peers.
|
|
|
|
|
- //pub async fn fetch_exluding_schemes(
|
|
|
|
|
- // &self,
|
|
|
|
|
- // schemes: &[String],
|
|
|
|
|
- // limit: Option<usize>,
|
|
|
|
|
- //) -> Vec<Url> {
|
|
|
|
|
- // let addrs = self.addrs.read().await;
|
|
|
|
|
- // let mut limit = match limit {
|
|
|
|
|
- // Some(l) => l.min(addrs.len()),
|
|
|
|
|
- // None => addrs.len(),
|
|
|
|
|
- // };
|
|
|
|
|
- // let mut ret = vec![];
|
|
|
|
|
-
|
|
|
|
|
- // if limit == 0 {
|
|
|
|
|
- // return ret
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // for addr in addrs.iter() {
|
|
|
|
|
- // if !schemes.contains(&addr.scheme().to_string()) {
|
|
|
|
|
- // ret.push(addr.clone());
|
|
|
|
|
- // limit -= 1;
|
|
|
|
|
- // if limit == 0 {
|
|
|
|
|
- // return ret
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // // If we didn't find any, pick some from the quarantine zone
|
|
|
|
|
- // if ret.is_empty() {
|
|
|
|
|
- // for addr in self.quarantine.read().await.keys() {
|
|
|
|
|
- // if !schemes.contains(&addr.scheme().to_string()) {
|
|
|
|
|
- // ret.push(addr.clone());
|
|
|
|
|
- // limit -= 1;
|
|
|
|
|
- // if limit == 0 {
|
|
|
|
|
- // break
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // ret
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
|
|
+ /// Get up to limit peers that don't match the given transport schemes from the whitelist.
|
|
|
|
|
+ /// If limit was not provided, return all matching peers.
|
|
|
pub async fn whitelist_fetch_excluding_schemes(
|
|
pub async fn whitelist_fetch_excluding_schemes(
|
|
|
&self,
|
|
&self,
|
|
|
schemes: &[String],
|
|
schemes: &[String],
|
|
@@ -971,87 +602,6 @@ mod tests {
|
|
|
use super::{super::settings::Settings, *};
|
|
use super::{super::settings::Settings, *};
|
|
|
use std::time::SystemTime;
|
|
use std::time::SystemTime;
|
|
|
|
|
|
|
|
- //#[test]
|
|
|
|
|
- //fn test_store_localnet() {
|
|
|
|
|
- // smol::block_on(async {
|
|
|
|
|
- // let settings = Settings {
|
|
|
|
|
- // localnet: true,
|
|
|
|
|
- // external_addrs: vec![
|
|
|
|
|
- // Url::parse("tcp://foo.bar:123").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://lol.cat:321").unwrap(),
|
|
|
|
|
- // ],
|
|
|
|
|
- // ..Default::default()
|
|
|
|
|
- // };
|
|
|
|
|
-
|
|
|
|
|
- // let hosts = Hosts::new(Arc::new(settings.clone()));
|
|
|
|
|
- // hosts.store(&settings.external_addrs).await;
|
|
|
|
|
- // for i in settings.external_addrs {
|
|
|
|
|
- // assert!(hosts.contains(&i).await);
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // let local_hosts = vec![
|
|
|
|
|
- // Url::parse("tcp://localhost:3921").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://127.0.0.1:23957").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://[::1]:21481").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://192.168.10.65:311").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://0.0.0.0:2312").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://255.255.255.255:2131").unwrap(),
|
|
|
|
|
- // ];
|
|
|
|
|
- // hosts.store(&local_hosts).await;
|
|
|
|
|
- // for i in local_hosts {
|
|
|
|
|
- // assert!(hosts.contains(&i).await);
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- // let remote_hosts = vec![
|
|
|
|
|
- // Url::parse("tcp://dark.fi:80").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://top.kek:111").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://http.cat:401").unwrap(),
|
|
|
|
|
- // ];
|
|
|
|
|
- // hosts.store(&remote_hosts).await;
|
|
|
|
|
- // for i in remote_hosts {
|
|
|
|
|
- // assert!(hosts.contains(&i).await);
|
|
|
|
|
- // }
|
|
|
|
|
- // });
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
- //#[test]
|
|
|
|
|
- //fn test_store() {
|
|
|
|
|
- // smol::block_on(async {
|
|
|
|
|
- // let settings = Settings {
|
|
|
|
|
- // localnet: false,
|
|
|
|
|
- // external_addrs: vec![
|
|
|
|
|
- // Url::parse("tcp://foo.bar:123").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://lol.cat:321").unwrap(),
|
|
|
|
|
- // ],
|
|
|
|
|
- // ..Default::default()
|
|
|
|
|
- // };
|
|
|
|
|
-
|
|
|
|
|
- // let hosts = Hosts::new(Arc::new(settings.clone()));
|
|
|
|
|
- // hosts.store(&settings.external_addrs).await;
|
|
|
|
|
- // assert!(hosts.is_empty().await);
|
|
|
|
|
-
|
|
|
|
|
- // let local_hosts = vec![
|
|
|
|
|
- // Url::parse("tcp://localhost:3921").unwrap(),
|
|
|
|
|
- // Url::parse("tor://[::1]:21481").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://192.168.10.65:311").unwrap(),
|
|
|
|
|
- // Url::parse("tcp+tls://0.0.0.0:2312").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://255.255.255.255:2131").unwrap(),
|
|
|
|
|
- // ];
|
|
|
|
|
- // hosts.store(&local_hosts).await;
|
|
|
|
|
- // assert!(hosts.is_empty().await);
|
|
|
|
|
-
|
|
|
|
|
- // let remote_hosts = vec![
|
|
|
|
|
- // Url::parse("tcp://dark.fi:80").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://http.cat:401").unwrap(),
|
|
|
|
|
- // Url::parse("tcp://foo.bar:111").unwrap(),
|
|
|
|
|
- // ];
|
|
|
|
|
- // hosts.store(&remote_hosts).await;
|
|
|
|
|
- // assert!(hosts.contains(&remote_hosts[0]).await);
|
|
|
|
|
- // assert!(hosts.contains(&remote_hosts[1]).await);
|
|
|
|
|
- // assert!(!hosts.contains(&remote_hosts[2]).await);
|
|
|
|
|
- // });
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
#[test]
|
|
#[test]
|
|
|
fn test_is_local_host() {
|
|
fn test_is_local_host() {
|
|
|
smol::block_on(async {
|
|
smol::block_on(async {
|