store.rs 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{
  19. collections::{HashMap, HashSet},
  20. fs,
  21. fs::File,
  22. sync::Arc,
  23. time::UNIX_EPOCH,
  24. };
  25. use log::{debug, error, info, trace, warn};
  26. use rand::{prelude::IteratorRandom, rngs::OsRng, Rng};
  27. use smol::lock::RwLock;
  28. use url::Url;
  29. use super::super::{p2p::P2pPtr, settings::SettingsPtr};
  30. use crate::{
  31. system::{Subscriber, SubscriberPtr, Subscription},
  32. util::{
  33. file::{load_file, save_file},
  34. path::expand_path,
  35. },
  36. Result,
  37. };
  38. /// Atomic pointer to hosts object
  39. pub type HostsPtr = Arc<Hosts>;
  40. // An array containing all possible local host strings
  41. // TODO: This could perhaps be more exhaustive?
  42. pub const LOCAL_HOST_STRS: [&str; 2] = ["localhost", "localhost.localdomain"];
  43. const WHITELIST_MAX_LEN: usize = 5000;
  44. const GREYLIST_MAX_LEN: usize = 2000;
  45. /// Manages a store of network addresses
  46. // TODO: Test the performance overhead of using vectors for white/grey/anchor lists.
  47. // TODO: Check whether anchorlist has a max size in Monero.
  48. // TODO: we can probably clean up a lot of the repetitive code in this module.
  49. pub struct Hosts {
  50. /// Intermediary node list that is periodically probed and updated to whitelist.
  51. pub greylist: RwLock<Vec<(Url, u64)>>,
  52. /// Recently seen hosts. Shared with other nodes.
  53. pub whitelist: RwLock<Vec<(Url, u64)>>,
  54. /// Nodes to which we have already been able to establish a connection.
  55. pub anchorlist: RwLock<Vec<(Url, u64)>>,
  56. /// Peers we reject from connecting to
  57. rejected: RwLock<HashSet<String>>,
  58. /// Peers that are currently being removed from the hostlist
  59. migrating: RwLock<HashSet<Url>>,
  60. /// Subscriber listening for store updates
  61. store_subscriber: SubscriberPtr<usize>,
  62. /// Pointer to configured P2P settings
  63. settings: SettingsPtr,
  64. }
  65. impl Hosts {
  66. /// Create a new hosts list>
  67. pub fn new(settings: SettingsPtr) -> HostsPtr {
  68. Arc::new(Self {
  69. greylist: RwLock::new(Vec::new()),
  70. whitelist: RwLock::new(Vec::new()),
  71. anchorlist: RwLock::new(Vec::new()),
  72. rejected: RwLock::new(HashSet::new()),
  73. migrating: RwLock::new(HashSet::new()),
  74. store_subscriber: Subscriber::new(),
  75. settings,
  76. })
  77. }
  78. /// Loops through greylist addresses to find an outbound address that we can
  79. /// connect to. Check whether the address is valid by making sure it isn't
  80. /// our own inbound address, then checks whether it is already connected
  81. /// (exists) or connecting (pending).
  82. /// Lastly adds matching address to the pending list.
  83. pub async fn greylist_fetch_address(&self, transports: &[String]) -> Vec<(Url, u64)> {
  84. trace!(target: "store", "greylist_fetch_address() [START]");
  85. // Collect hosts
  86. let mut hosts = vec![];
  87. // If transport mixing is enabled, then for example we're allowed to
  88. // use tor:// to connect to tcp:// and tor+tls:// to connect to tcp+tls://.
  89. // However, **do not** mix tor:// and tcp+tls://, nor tor+tls:// and tcp://.
  90. let transport_mixing = self.settings.transport_mixing;
  91. macro_rules! mix_transport {
  92. ($a:expr, $b:expr) => {
  93. if transports.contains(&$a.to_string()) && transport_mixing {
  94. let mut a_to_b =
  95. self.greylist_fetch_with_schemes(&[$b.to_string()], None).await;
  96. for (addr, last_seen) in a_to_b.iter_mut() {
  97. addr.set_scheme($a).unwrap();
  98. hosts.push((addr.clone(), last_seen.clone()));
  99. }
  100. }
  101. };
  102. }
  103. mix_transport!("tor", "tcp");
  104. mix_transport!("tor+tls", "tcp+tls");
  105. mix_transport!("nym", "tcp");
  106. mix_transport!("nym+tls", "tcp+tls");
  107. // And now the actual requested transports
  108. for (addr, last_seen) in self.greylist_fetch_with_schemes(transports, None).await {
  109. hosts.push((addr, last_seen));
  110. }
  111. hosts
  112. }
  113. /// Loops through whitelist addresses to find an outbound address that we can
  114. /// connect to. Check whether the address is valid by making sure it isn't
  115. /// our own inbound address, then checks whether it is already connected
  116. /// (exists) or connecting (pending).
  117. /// Lastly adds matching address to the pending list.
  118. pub async fn whitelist_fetch_address(&self, transports: &[String]) -> Vec<(Url, u64)> {
  119. trace!(target: "store", "whitelist_fetch_address() [START]");
  120. // Collect hosts
  121. let mut hosts = vec![];
  122. // If transport mixing is enabled, then for example we're allowed to
  123. // use tor:// to connect to tcp:// and tor+tls:// to connect to tcp+tls://.
  124. // However, **do not** mix tor:// and tcp+tls://, nor tor+tls:// and tcp://.
  125. let transport_mixing = self.settings.transport_mixing;
  126. macro_rules! mix_transport {
  127. ($a:expr, $b:expr) => {
  128. if transports.contains(&$a.to_string()) && transport_mixing {
  129. let mut a_to_b =
  130. self.whitelist_fetch_with_schemes(&[$b.to_string()], None).await;
  131. for (addr, last_seen) in a_to_b.iter_mut() {
  132. addr.set_scheme($a).unwrap();
  133. hosts.push((addr.clone(), last_seen.clone()));
  134. }
  135. }
  136. };
  137. }
  138. mix_transport!("tor", "tcp");
  139. mix_transport!("tor+tls", "tcp+tls");
  140. mix_transport!("nym", "tcp");
  141. mix_transport!("nym+tls", "tcp+tls");
  142. // And now the actual requested transports
  143. for (addr, last_seen) in self.whitelist_fetch_with_schemes(transports, None).await {
  144. hosts.push((addr, last_seen));
  145. }
  146. trace!(target: "store::whitelist_fetch_address()",
  147. "Grabbed hosts, length: {}", hosts.len());
  148. hosts
  149. }
  150. /// Loops through anchorlist addresses to find an outbound address that we can
  151. /// connect to. Check whether the address is valid by making sure it isn't
  152. /// our own inbound address, then checks whether it is already connected
  153. /// (exists) or connecting (pending).
  154. /// Lastly adds matching address to the pending list.
  155. pub async fn anchorlist_fetch_address(&self, transports: &[String]) -> Vec<(Url, u64)> {
  156. trace!(target: "store", "anchorlist_fetch_address() [START]");
  157. // Collect hosts
  158. let mut hosts = vec![];
  159. // If transport mixing is enabled, then for example we're allowed to
  160. // use tor:// to connect to tcp:// and tor+tls:// to connect to tcp+tls://.
  161. // However, **do not** mix tor:// and tcp+tls://, nor tor+tls:// and tcp://.
  162. let transport_mixing = self.settings.transport_mixing;
  163. macro_rules! mix_transport {
  164. ($a:expr, $b:expr) => {
  165. if transports.contains(&$a.to_string()) && transport_mixing {
  166. let mut a_to_b =
  167. self.anchorlist_fetch_with_schemes(&[$b.to_string()], None).await;
  168. for (addr, last_seen) in a_to_b.iter_mut() {
  169. addr.set_scheme($a).unwrap();
  170. hosts.push((addr.clone(), last_seen.clone()));
  171. }
  172. }
  173. };
  174. }
  175. mix_transport!("tor", "tcp");
  176. mix_transport!("tor+tls", "tcp+tls");
  177. mix_transport!("nym", "tcp");
  178. mix_transport!("nym+tls", "tcp+tls");
  179. // And now the actual requested transports
  180. for (addr, last_seen) in self.anchorlist_fetch_with_schemes(transports, None).await {
  181. hosts.push((addr, last_seen));
  182. }
  183. trace!(target: "store::anchorlist_fetch_address()",
  184. "Grabbed hosts, length: {}", hosts.len());
  185. hosts
  186. }
  187. pub async fn check_address_with_lock(
  188. &self,
  189. p2p: P2pPtr,
  190. hosts: Vec<(Url, u64)>,
  191. ) -> Option<(Url, u64)> {
  192. // Try to find an unused host in the set.
  193. for (host, last_seen) in hosts {
  194. debug!(target: "store::check_address_with_lock()",
  195. "Starting checks");
  196. // Check if we already have this connection established
  197. if p2p.exists(&host).await {
  198. debug!(
  199. target: "store::check_address_with_lock()",
  200. "Host '{}' exists so skipping",
  201. host
  202. );
  203. continue
  204. }
  205. // Check if we already have this configured as a manual peer
  206. if self.settings.peers.contains(&host) {
  207. debug!(
  208. target: "store::check_address_with_lock()",
  209. "Host '{}' configured as manual peer so skipping",
  210. host
  211. );
  212. continue
  213. }
  214. // Obtain a lock on this address to prevent duplicate connection
  215. if !p2p.add_pending(&host).await {
  216. debug!(
  217. target: "store::check_address_with_lock()",
  218. "Host '{}' pending so skipping",
  219. host
  220. );
  221. continue
  222. }
  223. debug!(
  224. target: "store::check_address_with_lock()",
  225. "Found valid host {}",
  226. host
  227. );
  228. return Some((host.clone(), last_seen))
  229. }
  230. None
  231. }
  232. /// Upgrade a connection to the anchorlist. Called after a connection has been successfully
  233. /// established in Outbound and Manual sessions.
  234. pub async fn upgrade_host(&self, addr: &Url) {
  235. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  236. self.anchorlist_store_or_update(&[(addr.clone(), last_seen)]).await;
  237. }
  238. /// Remove an entry from the hostlist. Called when we cannot establish a connection to a host or
  239. /// when a pre-existing connection disconnects.
  240. pub async fn remove_host(&self, addr: &Url) {
  241. debug!(target: "store::remove_host", "Removing host {}", addr);
  242. self.mark_migrating(addr).await;
  243. // Remove channel from anchorlist
  244. if self.anchorlist_contains(addr).await {
  245. debug!(target: "store::remove_host", "Removing from anchorlist {}", addr);
  246. let index = self
  247. .get_anchorlist_index_at_addr(addr.clone())
  248. .await
  249. .expect("Expected anchorlist index to exist");
  250. self.anchorlist_remove(addr, index).await;
  251. }
  252. // Remove channel from whitelist
  253. if self.whitelist_contains(addr).await {
  254. debug!(target: "store::remove_host", "Removing from whitelist {}", addr);
  255. let index = self
  256. .get_whitelist_index_at_addr(addr.clone())
  257. .await
  258. .expect("Expected whitelist index to exist");
  259. self.whitelist_remove(addr, index).await;
  260. }
  261. // Remove channel the greylist
  262. if self.greylist_contains(addr).await {
  263. debug!(target: "store::remove_host", "Removing from greylist {}", addr);
  264. let index = self
  265. .get_greylist_index_at_addr(addr.clone())
  266. .await
  267. .expect("Expected greylist index to exist");
  268. self.greylist_remove(addr, index).await;
  269. }
  270. self.unmark_migrating(addr).await;
  271. }
  272. /// Stores an address on the greylist or updates its last_seen field if we already
  273. /// have the address.
  274. pub async fn greylist_store_or_update(&self, addrs: &[(Url, u64)]) {
  275. trace!(target: "store::greylist_store_or_update()", "[START]");
  276. // Filter addresses before writing to the greylist.
  277. let filtered_addrs = self.filter_addresses(addrs).await;
  278. let filtered_addrs_len = filtered_addrs.len();
  279. for (addr, last_seen) in filtered_addrs {
  280. if !self.greylist_contains(&addr).await {
  281. debug!(target: "store::greylist_store_or_update()",
  282. "We do not have this entry in the hostlist. Adding to store...");
  283. self.greylist_store(addr.clone(), last_seen).await;
  284. } else {
  285. debug!(target: "store::greylist_store_or_update()",
  286. "We have this entry in the greylist. Updating last seen...");
  287. let index = self
  288. .get_greylist_index_at_addr(addr.clone())
  289. .await
  290. .expect("Expected greylist entry to exist");
  291. self.greylist_update_last_seen(&addr, last_seen, index).await;
  292. self.store_subscriber.notify(filtered_addrs_len).await;
  293. }
  294. }
  295. }
  296. /// Stores an address on the whitelist or updates its last_seen field if we already
  297. /// have the address.
  298. pub async fn whitelist_store_or_update(&self, addrs: &[(Url, u64)]) {
  299. trace!(target: "store::whitelist_store_or_update()", "[START]");
  300. // No address filtering for whitelist (whitelist is created from greylist)
  301. for (addr, last_seen) in addrs {
  302. if !self.whitelist_contains(addr).await {
  303. debug!(target: "store::whitelist_store_or_update()",
  304. "We do not have this entry in the whitelist. Adding to store...");
  305. self.whitelist_store(addr.clone(), *last_seen).await;
  306. } else {
  307. debug!(target: "store::whitelist_store_or_update()",
  308. "We have this entry in the whitelist. Updating last seen...");
  309. let index = self
  310. .get_whitelist_index_at_addr(addr.clone())
  311. .await
  312. .expect("Expected whitelist entry to exist");
  313. self.whitelist_update_last_seen(addr, *last_seen, index).await;
  314. }
  315. }
  316. }
  317. /// Stores an address on the anchorlist or updates its last_seen field if we already
  318. /// have the address.
  319. pub async fn anchorlist_store_or_update(&self, addrs: &[(Url, u64)]) {
  320. trace!(target: "store::anchor_store_or_update()", "[START]");
  321. // No address filtering for anchorlist (contains addresses we have already connected to)
  322. for (addr, last_seen) in addrs {
  323. if !self.anchorlist_contains(addr).await {
  324. debug!(target: "store::anchorlist_store_or_update()",
  325. "We do not have this entry in the whitelist. Adding to store...");
  326. self.anchorlist_store(addr.clone(), *last_seen).await;
  327. } else {
  328. debug!(target: "store::anchorlist_store_or_update()",
  329. "We have this entry in the anchorlist. Updating last seen...");
  330. let index = self
  331. .get_anchorlist_index_at_addr(addr.clone())
  332. .await
  333. .expect("Expected anchorlist entry to exist");
  334. self.anchorlist_update_last_seen(addr, *last_seen, index).await;
  335. }
  336. }
  337. }
  338. /// Append host to the greylist. Called on learning of a new peer.
  339. pub async fn greylist_store(&self, addr: Url, last_seen: u64) {
  340. trace!(target: "store::greylist_store()", "hosts::greylist_store() [START]");
  341. let mut greylist = self.greylist.write().await;
  342. // Remove oldest element if the greylist reaches max size.
  343. if greylist.len() == GREYLIST_MAX_LEN {
  344. let last_entry = greylist.pop().unwrap();
  345. debug!(target: "store::greylist_store()", "Greylist reached max size. Removed {:?}", last_entry);
  346. }
  347. debug!(target: "store::greylist_store()", "Inserting {}", addr);
  348. greylist.push((addr, last_seen));
  349. // Sort the list by last_seen.
  350. greylist.sort_by_key(|entry| entry.1);
  351. greylist.reverse();
  352. trace!(target: "store::greylist_store()", "[END]");
  353. }
  354. /// Append host to the whitelist. Called after a successful interaction with an online peer.
  355. pub async fn whitelist_store(&self, addr: Url, last_seen: u64) {
  356. trace!(target: "store::whitelist_store()", "[START]");
  357. let mut whitelist = self.whitelist.write().await;
  358. // Remove oldest element if the whitelist reaches max size.
  359. if whitelist.len() == WHITELIST_MAX_LEN {
  360. let last_entry = whitelist.pop().unwrap();
  361. debug!(target: "store::whitelist_store()", "Whitelist reached max size. Removed {:?}", last_entry);
  362. }
  363. trace!(target: "store::whitelist_store()", "Inserting {}. Last seen {:?}", addr, last_seen);
  364. whitelist.push((addr, last_seen));
  365. // Sort the list by last_seen.
  366. whitelist.sort_by_key(|entry| entry.1);
  367. whitelist.reverse();
  368. trace!(target: "store::whitelist_store()", "[END]");
  369. }
  370. /// Append host to the anchorlist. Called after we have successfully established a connection
  371. /// to a peer.
  372. pub async fn anchorlist_store(&self, addr: Url, last_seen: u64) {
  373. trace!(target: "store::anchorlist_store()", "[START]");
  374. let mut anchorlist = self.anchorlist.write().await;
  375. trace!(target: "store::anchorlist_store()", "Inserting {}", addr);
  376. anchorlist.push((addr, last_seen));
  377. // Sort the list by last_seen.
  378. anchorlist.sort_by_key(|entry| entry.1);
  379. anchorlist.reverse();
  380. trace!(target: "store::anchorlist_store()", "[END]");
  381. }
  382. /// Update the last_seen field of a peer on the greylist.
  383. pub async fn greylist_update_last_seen(&self, addr: &Url, last_seen: u64, index: usize) {
  384. trace!(target: "store::greylist_update_last_seen()", "[START]");
  385. let mut greylist = self.greylist.write().await;
  386. greylist[index] = (addr.clone(), last_seen);
  387. // Sort the list by last_seen.
  388. greylist.sort_by_key(|entry| entry.1);
  389. greylist.reverse();
  390. trace!(target: "store::greylist_update_last_seen()", "[END]");
  391. }
  392. /// Update the last_seen field of a peer on the whitelist.
  393. pub async fn whitelist_update_last_seen(&self, addr: &Url, last_seen: u64, index: usize) {
  394. trace!(target: "store::whitelist_update_last_seen()", "[START]");
  395. let mut whitelist = self.whitelist.write().await;
  396. whitelist[index] = (addr.clone(), last_seen);
  397. // Sort the list by last_seen.
  398. whitelist.sort_by_key(|entry| entry.1);
  399. whitelist.reverse();
  400. trace!(target: "store::whitelist_update_last_seen()", "[END]");
  401. }
  402. /// Update the last_seen field of a peer on the anchorlist.
  403. pub async fn anchorlist_update_last_seen(&self, addr: &Url, last_seen: u64, index: usize) {
  404. trace!(target: "store::anchorlist_update_last_seen()", "[START]");
  405. let mut anchorlist = self.anchorlist.write().await;
  406. anchorlist[index] = (addr.clone(), last_seen);
  407. // Sort the list by last_seen.
  408. anchorlist.sort_by_key(|entry| entry.1);
  409. anchorlist.reverse();
  410. trace!(target: "store::anchorlist_update_last_seen()", "[END]");
  411. }
  412. /// Remove an entry from the greylist.
  413. pub async fn greylist_remove(&self, addr: &Url, index: usize) {
  414. debug!(target: "store::greylist_remove", "Removing peer {} from greylist", addr);
  415. self.greylist.write().await.remove(index);
  416. }
  417. /// Remove an entry from the whitelist.
  418. pub async fn whitelist_remove(&self, addr: &Url, index: usize) {
  419. debug!(target: "store::whitelist_remove", "Removing peer {} from whitelist", addr);
  420. self.whitelist.write().await.remove(index);
  421. }
  422. /// Remove an entry from the anchorlist.
  423. pub async fn anchorlist_remove(&self, addr: &Url, index: usize) {
  424. debug!(target: "store::anchorlist_remove", "Removing peer {} from anchorlist", addr);
  425. self.anchorlist.write().await.remove(index);
  426. }
  427. pub async fn subscribe_store(&self) -> Result<Subscription<usize>> {
  428. let sub = self.store_subscriber.clone().subscribe().await;
  429. Ok(sub)
  430. }
  431. // Verify whether a URL is local.
  432. // NOTE: This function is stateless and not specific to
  433. // `Hosts`. For this reason, it might make more sense
  434. // to move this function to a more appropriate location
  435. // in the codebase.
  436. /// Check whether a URL is local host
  437. pub async fn is_local_host(&self, url: Url) -> bool {
  438. // Reject Urls without host strings.
  439. if url.host_str().is_none() {
  440. return false
  441. }
  442. // We do this hack in order to parse IPs properly.
  443. // https://github.com/whatwg/url/issues/749
  444. let addr = Url::parse(&url.as_str().replace(url.scheme(), "http")).unwrap();
  445. // Filter private IP ranges
  446. match addr.host().unwrap() {
  447. url::Host::Ipv4(ip) => {
  448. if !ip.is_global() {
  449. return true
  450. }
  451. }
  452. url::Host::Ipv6(ip) => {
  453. if !ip.is_global() {
  454. return true
  455. }
  456. }
  457. url::Host::Domain(d) => {
  458. if LOCAL_HOST_STRS.contains(&d) {
  459. return true
  460. }
  461. }
  462. }
  463. false
  464. }
  465. /// Filter given addresses based on certain rulesets and validity.
  466. async fn filter_addresses(&self, addrs: &[(Url, u64)]) -> Vec<(Url, u64)> {
  467. trace!(target: "store::filter_addresses()", "Filtering addrs: {:?}", addrs);
  468. let mut ret = vec![];
  469. let localnet = self.settings.localnet;
  470. 'addr_loop: for (addr_, last_seen) in addrs {
  471. // Validate that the format is `scheme://host_str:port`
  472. if addr_.host_str().is_none() ||
  473. addr_.port().is_none() ||
  474. addr_.cannot_be_a_base() ||
  475. addr_.path_segments().is_some()
  476. {
  477. continue
  478. }
  479. if self.is_rejected(addr_).await {
  480. debug!(target: "store::filter_addresses()", "Peer {} is rejected", addr_);
  481. continue
  482. }
  483. let host_str = addr_.host_str().unwrap();
  484. if !localnet {
  485. // Our own external addresses should never enter the hosts set.
  486. for ext in &self.settings.external_addrs {
  487. if host_str == ext.host_str().unwrap() {
  488. continue 'addr_loop
  489. }
  490. }
  491. }
  492. // On localnet, make sure ours ports don't enter the host set.
  493. for ext in &self.settings.external_addrs {
  494. if addr_.port() == ext.port() {
  495. continue 'addr_loop
  496. }
  497. }
  498. // We do this hack in order to parse IPs properly.
  499. // https://github.com/whatwg/url/issues/749
  500. let addr = Url::parse(&addr_.as_str().replace(addr_.scheme(), "http")).unwrap();
  501. // Filter non-global ranges if we're not allowing localnet.
  502. // Should never be allowed in production, so we don't really care
  503. // about some of them (e.g. 0.0.0.0, or broadcast, etc.).
  504. if !localnet && self.is_local_host(addr).await {
  505. continue
  506. }
  507. match addr_.scheme() {
  508. // Validate that the address is an actual onion.
  509. #[cfg(feature = "p2p-tor")]
  510. "tor" | "tor+tls" => {
  511. use std::str::FromStr;
  512. if tor_hscrypto::pk::HsId::from_str(host_str).is_err() {
  513. continue
  514. }
  515. trace!(target: "store::filter_addresses()", "[Tor] Valid: {}", host_str);
  516. }
  517. #[cfg(feature = "p2p-nym")]
  518. "nym" | "nym+tls" => continue, // <-- Temp skip
  519. #[cfg(feature = "p2p-tcp")]
  520. "tcp" | "tcp+tls" => {
  521. trace!(target: "store::filter_addresses()", "[TCP] Valid: {}", host_str);
  522. }
  523. _ => continue,
  524. }
  525. ret.push((addr_.clone(), *last_seen));
  526. }
  527. ret
  528. }
  529. /// Check if a given peer (URL) is in the set of rejected hosts
  530. pub async fn is_rejected(&self, peer: &Url) -> bool {
  531. // Skip lookup for UNIX sockets and localhost connections
  532. // as they should never belong to the list of rejected URLs.
  533. let Some(hostname) = peer.host_str() else { return false };
  534. if self.is_local_host(peer.clone()).await {
  535. return false
  536. }
  537. self.rejected.read().await.contains(hostname)
  538. }
  539. /// Mark a peer as rejected by adding it to the set of rejected URLs.
  540. pub async fn mark_rejected(&self, peer: &Url) {
  541. // We ignore UNIX sockets here so we will just work
  542. // with stuff that has host_str().
  543. if let Some(hostname) = peer.host_str() {
  544. // Localhost connections should not be rejected
  545. // This however allows any Tor and Nym connections.
  546. if self.is_local_host(peer.clone()).await {
  547. return
  548. }
  549. self.rejected.write().await.insert(hostname.to_string());
  550. }
  551. }
  552. /// Unmark a rejected peer
  553. pub async fn unmark_rejected(&self, peer: &Url) {
  554. if let Some(hostname) = peer.host_str() {
  555. self.rejected.write().await.remove(hostname);
  556. }
  557. }
  558. /// Peer that is currently being removed from hostlists.
  559. pub async fn is_migrating(&self, peer: &Url) -> bool {
  560. self.migrating.read().await.contains(peer)
  561. }
  562. /// Mark a peer as currently migrating.
  563. pub async fn mark_migrating(&self, peer: &Url) {
  564. self.migrating.write().await.insert(peer.clone());
  565. }
  566. /// Unmark a migrating peer.
  567. pub async fn unmark_migrating(&self, peer: &Url) {
  568. self.migrating.write().await.remove(peer);
  569. }
  570. /// Check if the greylist is empty.
  571. pub async fn is_empty_greylist(&self) -> bool {
  572. self.greylist.read().await.is_empty()
  573. }
  574. /// Check if the whitelist is empty.
  575. pub async fn is_empty_whitelist(&self) -> bool {
  576. self.whitelist.read().await.is_empty()
  577. }
  578. /// Check if the anchorlist is empty.
  579. pub async fn is_empty_anchorlist(&self) -> bool {
  580. self.anchorlist.read().await.is_empty()
  581. }
  582. /// Check if the hostlist is empty.
  583. pub async fn is_empty_hostlist(&self) -> bool {
  584. self.is_empty_greylist().await &&
  585. self.is_empty_whitelist().await &&
  586. self.is_empty_anchorlist().await
  587. }
  588. /// Check if host is in the greylist
  589. pub async fn greylist_contains(&self, addr: &Url) -> bool {
  590. self.greylist.read().await.iter().any(|(u, _t)| u == addr)
  591. }
  592. /// Check if host is in the whitelist
  593. pub async fn whitelist_contains(&self, addr: &Url) -> bool {
  594. self.whitelist.read().await.iter().any(|(u, _t)| u == addr)
  595. }
  596. /// Check if host is in the anchorlist
  597. pub async fn anchorlist_contains(&self, addr: &Url) -> bool {
  598. self.anchorlist.read().await.iter().any(|(u, _t)| u == addr)
  599. }
  600. /// Get the index for a given addr on the greylist.
  601. pub async fn get_greylist_index_at_addr(&self, addr: Url) -> Option<usize> {
  602. self.greylist.read().await.iter().position(|a| a.0 == addr)
  603. }
  604. /// Get the index for a given addr on the whitelist.
  605. pub async fn get_whitelist_index_at_addr(&self, addr: Url) -> Option<usize> {
  606. self.whitelist.read().await.iter().position(|a| a.0 == addr)
  607. }
  608. /// Get the index for a given addr on the anchorlist.
  609. pub async fn get_anchorlist_index_at_addr(&self, addr: Url) -> Option<usize> {
  610. self.anchorlist.read().await.iter().position(|a| a.0 == addr)
  611. }
  612. /// Get the entry for a given addr on the whitelist.
  613. pub async fn get_whitelist_entry_at_addr(&self, addr: &Url) -> Option<(Url, u64)> {
  614. self.whitelist
  615. .read()
  616. .await
  617. .iter()
  618. .find(|(url, _)| url == addr)
  619. .map(|(url, time)| (url.clone(), *time))
  620. }
  621. /// Get the entry for a given addr on the anchorlist.
  622. pub async fn get_anchorlist_entry_at_addr(&self, addr: &Url) -> Option<(Url, u64)> {
  623. self.anchorlist
  624. .read()
  625. .await
  626. .iter()
  627. .find(|(url, _)| url == addr)
  628. .map(|(url, time)| (url.clone(), *time))
  629. }
  630. /// Return all known whitelisted hosts
  631. pub async fn whitelist_fetch_all(&self) -> Vec<(Url, u64)> {
  632. self.whitelist.read().await.iter().cloned().collect()
  633. }
  634. /// Return all greylist and anchorlist hosts. Called on stop().
  635. /// Note: we do not return whitelist entries here since whitelist entries must go via the
  636. /// greylist refinery in the lifetime of the p2p network.
  637. pub async fn hostlist_fetch_safe(&self) -> HashMap<String, Vec<(Url, u64)>> {
  638. let mut hostlist = HashMap::new();
  639. hostlist.insert(
  640. "anchorlist".to_string(),
  641. self.anchorlist.read().await.iter().cloned().collect(),
  642. );
  643. hostlist
  644. .insert("greylist".to_string(), self.greylist.read().await.iter().cloned().collect());
  645. hostlist
  646. }
  647. /// Get up to n random peers from the whitelist.
  648. pub async fn whitelist_fetch_n_random(&self, n: u32) -> Vec<(Url, u64)> {
  649. let n = n as usize;
  650. if n == 0 {
  651. return vec![]
  652. }
  653. let addrs = self.whitelist.read().await;
  654. let urls = addrs.iter().choose_multiple(&mut OsRng, n.min(addrs.len()));
  655. urls.iter().map(|&url| url.clone()).collect()
  656. }
  657. /// Get a random peer from the greylist.
  658. pub async fn greylist_fetch_random(&self) -> ((Url, u64), usize) {
  659. let greylist = self.greylist.read().await;
  660. let position = rand::thread_rng().gen_range(0..greylist.len());
  661. let entry = &greylist[position];
  662. (entry.clone(), position)
  663. }
  664. /// Get a random peer from the whitelist.
  665. pub async fn whitelist_fetch_random(&self) -> ((Url, u64), usize) {
  666. let whitelist = self.whitelist.read().await;
  667. let position = rand::thread_rng().gen_range(0..whitelist.len());
  668. let entry = &whitelist[position];
  669. (entry.clone(), position)
  670. }
  671. /// Get the oldest entry from the whitelist.
  672. pub async fn whitelist_fetch_last(&self) -> ((Url, u64), usize) {
  673. let whitelist = self.whitelist.read().await;
  674. let position = whitelist.len() - 1;
  675. let entry = &whitelist[position];
  676. (entry.clone(), position)
  677. }
  678. /// Get a random greylist peer that matches the given transport schemes.
  679. pub async fn greylist_fetch_random_with_schemes(&self) -> ((Url, u64), usize) {
  680. trace!(target: "store::greylist_fetch_random_with_schemes", "[START]");
  681. // Retrieve all peers corresponding to that transport schemes
  682. let schemes = &self.settings.allowed_transports;
  683. let greylist = self.greylist_fetch_with_schemes(&schemes, None).await;
  684. let position = rand::thread_rng().gen_range(0..greylist.len());
  685. let entry = &greylist[position];
  686. (entry.clone(), position)
  687. }
  688. /// Get up to n random whitelist peers that match the given transport schemes.
  689. pub async fn whitelist_fetch_n_random_with_schemes(
  690. &self,
  691. schemes: &[String],
  692. n: u32,
  693. ) -> Vec<(Url, u64)> {
  694. let n = n as usize;
  695. if n == 0 {
  696. return vec![]
  697. }
  698. trace!(target: "store::whitelist_fetch_n_random_with_schemes", "[START]");
  699. // Retrieve all peers corresponding to that transport schemes
  700. let hosts = self.whitelist_fetch_with_schemes(schemes, None).await;
  701. if hosts.is_empty() {
  702. trace!(target: "store::whitelist_fetch_n_random_with_schemes",
  703. "Whitelist is empty {:?}! Exiting...", hosts);
  704. return hosts
  705. }
  706. // Grab random ones
  707. let urls = hosts.iter().choose_multiple(&mut OsRng, n.min(hosts.len()));
  708. urls.iter().map(|&url| url.clone()).collect()
  709. }
  710. /// Get up to limit peers that don't match the given transport schemes from the whitelist.
  711. /// If limit was not provided, return all matching peers.
  712. pub async fn whitelist_fetch_excluding_schemes(
  713. &self,
  714. schemes: &[String],
  715. limit: Option<usize>,
  716. ) -> Vec<(Url, u64)> {
  717. let addrs = self.whitelist.read().await;
  718. let mut limit = match limit {
  719. Some(l) => l.min(addrs.len()),
  720. None => addrs.len(),
  721. };
  722. let mut ret = vec![];
  723. if limit == 0 {
  724. return ret
  725. }
  726. for (addr, last_seen) in addrs.iter() {
  727. if !schemes.contains(&addr.scheme().to_string()) {
  728. ret.push((addr.clone(), *last_seen));
  729. limit -= 1;
  730. if limit == 0 {
  731. return ret
  732. }
  733. }
  734. }
  735. // If we didn't find any, pick some from the greylist
  736. if ret.is_empty() {
  737. for (addr, last_seen) in self.greylist.read().await.iter() {
  738. if !schemes.contains(&addr.scheme().to_string()) {
  739. ret.push((addr.clone(), *last_seen));
  740. limit -= 1;
  741. if limit == 0 {
  742. break
  743. }
  744. }
  745. }
  746. }
  747. ret
  748. }
  749. /// Get up to n random whitelisted peers that don't match the given transport schemes from the
  750. /// hosts set.
  751. pub async fn whitelist_fetch_n_random_excluding_schemes(
  752. &self,
  753. schemes: &[String],
  754. n: u32,
  755. ) -> Vec<(Url, u64)> {
  756. let n = n as usize;
  757. if n == 0 {
  758. return vec![]
  759. }
  760. trace!(target: "store::whitelist_fetch_excluding_schemes", "[START]");
  761. // Retrieve all peers not corresponding to that transport schemes
  762. let hosts = self.whitelist_fetch_excluding_schemes(schemes, None).await;
  763. if hosts.is_empty() {
  764. debug!(target: "store::whitelist_fetch_n_random_excluding_schemes",
  765. "No address without schemes found! Exiting...");
  766. return hosts
  767. }
  768. // Grab random ones
  769. let urls = hosts.iter().choose_multiple(&mut OsRng, n.min(hosts.len()));
  770. urls.iter().map(|&url| url.clone()).collect()
  771. }
  772. /// Get up to limit peers that match the given transport schemes from the greylist.
  773. /// If limit was not provided, return all matching peers.
  774. async fn greylist_fetch_with_schemes(
  775. &self,
  776. schemes: &[String],
  777. limit: Option<usize>,
  778. ) -> Vec<(Url, u64)> {
  779. debug!(target: "store::greylist_fetch_with_schemes", "[START]");
  780. let greylist = self.greylist.read().await;
  781. let mut limit = match limit {
  782. Some(l) => l.min(greylist.len()),
  783. None => greylist.len(),
  784. };
  785. let mut ret = vec![];
  786. if limit == 0 {
  787. return ret
  788. }
  789. for (addr, last_seen) in greylist.iter() {
  790. if schemes.contains(&addr.scheme().to_string()) {
  791. ret.push((addr.clone(), *last_seen));
  792. limit -= 1;
  793. if limit == 0 {
  794. debug!(target: "store::greylist_fetch_with_schemes", "Found matching greylist entry, returning");
  795. return ret
  796. }
  797. }
  798. }
  799. trace!(target: "store::greylist_fetch_with_schemes", "END");
  800. ret
  801. }
  802. /// Get up to limit peers that match the given transport schemes from the whitelist.
  803. /// If limit was not provided, return all matching peers.
  804. async fn whitelist_fetch_with_schemes(
  805. &self,
  806. schemes: &[String],
  807. limit: Option<usize>,
  808. ) -> Vec<(Url, u64)> {
  809. debug!(target: "store::whitelist_fetch_with_schemes", "[START]");
  810. let mut ret = vec![];
  811. if !self.is_empty_whitelist().await {
  812. let whitelist = self.whitelist.read().await;
  813. let mut parsed_limit = match limit {
  814. Some(l) => l.min(whitelist.len()),
  815. None => whitelist.len(),
  816. };
  817. for (addr, last_seen) in whitelist.iter() {
  818. if schemes.contains(&addr.scheme().to_string()) {
  819. ret.push((addr.clone(), *last_seen));
  820. parsed_limit -= 1;
  821. if parsed_limit == 0 {
  822. trace!(target: "store::whitelist_fetch_with_schemes",
  823. "Found matching white scheme, returning {:?}", ret);
  824. return ret
  825. }
  826. } else {
  827. warn!(target: "store::whitelist_fetch_with_schemes",
  828. "No matching schemes! Trying greylist...");
  829. return self.greylist_fetch_with_schemes(schemes, limit).await
  830. }
  831. }
  832. }
  833. // Whitelist is empty!
  834. if !self.is_empty_greylist().await {
  835. // Select from the greylist providing it's not empty.
  836. return self.greylist_fetch_with_schemes(schemes, limit).await
  837. }
  838. trace!(target: "store::whitelist_fetch_with_schemes", "END");
  839. ret
  840. }
  841. /// Get up to limit peers that match the given transport schemes from the anchorlist.
  842. /// If limit was not provided, return all matching peers.
  843. async fn anchorlist_fetch_with_schemes(
  844. &self,
  845. schemes: &[String],
  846. limit: Option<usize>,
  847. ) -> Vec<(Url, u64)> {
  848. trace!(target: "store::anchorlist_fetch_with_schemes", "[START]");
  849. let mut ret = vec![];
  850. // Select from the anchorlist providing it's not empty.
  851. if !self.is_empty_anchorlist().await {
  852. let anchorlist = self.anchorlist.read().await;
  853. let mut parsed_limit = match limit {
  854. Some(l) => l.min(anchorlist.len()),
  855. None => anchorlist.len(),
  856. };
  857. for (addr, last_seen) in anchorlist.iter() {
  858. if schemes.contains(&addr.scheme().to_string()) {
  859. ret.push((addr.clone(), *last_seen));
  860. parsed_limit -= 1;
  861. if parsed_limit == 0 {
  862. trace!(target: "store::anchorlist_fetch_with_schemes",
  863. "Found matching anchor scheme, returning {:?}", ret);
  864. return ret
  865. }
  866. } else {
  867. warn!(target: "store::anchorlist_fetch_with_schemes",
  868. "No matching schemes! Trying whitelist...");
  869. return self.whitelist_fetch_with_schemes(schemes, limit).await
  870. }
  871. }
  872. }
  873. // Select from the whitelist providing it's not empty.
  874. if !self.is_empty_whitelist().await {
  875. return self.whitelist_fetch_with_schemes(schemes, limit).await
  876. }
  877. // Select from the greyist providing it's not empty.
  878. if !self.is_empty_greylist().await {
  879. return self.greylist_fetch_with_schemes(schemes, limit).await
  880. }
  881. trace!(target: "store::anchorlist_fetch_with_schemes", "END");
  882. ret
  883. }
  884. /// Load the hostlist from a file.
  885. pub async fn load_hosts(&self) -> Result<()> {
  886. let path = expand_path(&self.settings.hostlist)?;
  887. if !path.exists() {
  888. if let Some(parent) = path.parent() {
  889. fs::create_dir_all(parent)?;
  890. }
  891. File::create(path.clone())?;
  892. }
  893. let contents = load_file(&path);
  894. if let Err(e) = contents {
  895. warn!(target: "store", "Failed retrieving saved hosts: {}", e);
  896. return Ok(())
  897. }
  898. for line in contents.unwrap().lines() {
  899. let data: Vec<&str> = line.split('\t').collect();
  900. let url = match Url::parse(data[1]) {
  901. Ok(u) => u,
  902. Err(e) => {
  903. debug!(target: "store", "load_hosts(): Skipping malformed URL {}", e);
  904. continue
  905. }
  906. };
  907. let last_seen = match data[2].parse::<u64>() {
  908. Ok(t) => t,
  909. Err(e) => {
  910. debug!(target: "store", "load_hosts(): Skipping malformed last seen {}", e);
  911. continue
  912. }
  913. };
  914. match data[0] {
  915. "greylist" => {
  916. self.greylist_store(url, last_seen).await;
  917. }
  918. "whitelist" => {
  919. self.whitelist_store(url, last_seen).await;
  920. }
  921. "anchorlist" => {
  922. self.anchorlist_store(url, last_seen).await;
  923. }
  924. _ => {
  925. debug!(target: "store", "load_hosts(): Malformed list name...");
  926. }
  927. }
  928. }
  929. Ok(())
  930. }
  931. /// Save the hostlist to a file. Whitelist gets written to the greylist to force
  932. /// whitelist entries through the refinery on start.
  933. pub async fn save_hosts(&self) -> Result<()> {
  934. let path = expand_path(&self.settings.hostlist)?;
  935. let mut tsv = String::new();
  936. let mut whitelist = vec![];
  937. // First gather all the whitelist entries we don't have in greylist.
  938. for (url, last_seen) in self.whitelist_fetch_all().await {
  939. if !self.greylist_contains(&url).await {
  940. whitelist.push((url, last_seen))
  941. }
  942. }
  943. // Collect the greylist and anchorlist entries, and append any whitelist entries to the
  944. // greylist before saving.
  945. for (name, mut list) in self.hostlist_fetch_safe().await {
  946. if name == *"greylist".to_string() {
  947. list.append(&mut whitelist)
  948. }
  949. for (url, last_seen) in list {
  950. tsv.push_str(&format!("{}\t{}\t{}\n", name, url, last_seen));
  951. }
  952. }
  953. if !tsv.eq("") {
  954. info!(target: "store", "Saving hosts to: {:?}",
  955. path);
  956. if let Err(e) = save_file(&path, &tsv) {
  957. error!(target: "store", "Failed saving hosts: {}", e);
  958. }
  959. }
  960. Ok(())
  961. }
  962. }
  963. #[cfg(test)]
  964. mod tests {
  965. use super::{
  966. super::super::{settings::Settings, P2p},
  967. *,
  968. };
  969. use crate::system::sleep;
  970. use smol::Executor;
  971. use std::{sync::Arc, time::UNIX_EPOCH};
  972. #[test]
  973. fn test_is_local_host() {
  974. smol::block_on(async {
  975. let settings = Settings {
  976. localnet: false,
  977. external_addrs: vec![
  978. Url::parse("tcp://foo.bar:123").unwrap(),
  979. Url::parse("tcp://lol.cat:321").unwrap(),
  980. ],
  981. ..Default::default()
  982. };
  983. let hosts = Hosts::new(Arc::new(settings.clone()));
  984. let local_hosts: Vec<Url> = vec![
  985. Url::parse("tcp://localhost").unwrap(),
  986. Url::parse("tcp://127.0.0.1").unwrap(),
  987. Url::parse("tcp+tls://[::1]").unwrap(),
  988. Url::parse("tcp://localhost.localdomain").unwrap(),
  989. Url::parse("tcp://192.168.10.65").unwrap(),
  990. ];
  991. for host in local_hosts {
  992. eprintln!("{}", host);
  993. assert!(hosts.is_local_host(host).await);
  994. }
  995. let remote_hosts: Vec<Url> = vec![
  996. Url::parse("https://dyne.org").unwrap(),
  997. Url::parse("tcp://77.168.10.65:2222").unwrap(),
  998. Url::parse("tcp://[2345:0425:2CA1:0000:0000:0567:5673:23b5]").unwrap(),
  999. Url::parse("http://eweiibe6tdjsdprb4px6rqrzzcsi22m4koia44kc5pcjr7nec2rlxyad.onion")
  1000. .unwrap(),
  1001. ];
  1002. for host in remote_hosts {
  1003. assert!(!(hosts.is_local_host(host).await))
  1004. }
  1005. });
  1006. }
  1007. #[test]
  1008. fn test_greylist_store() {
  1009. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  1010. smol::block_on(async {
  1011. let settings = Settings {
  1012. localnet: false,
  1013. external_addrs: vec![
  1014. Url::parse("tcp://foo.bar:123").unwrap(),
  1015. Url::parse("tcp://lol.cat:321").unwrap(),
  1016. ],
  1017. ..Default::default()
  1018. };
  1019. let hosts = Hosts::new(Arc::new(settings.clone()));
  1020. for addr in settings.external_addrs {
  1021. hosts.greylist_store(addr, last_seen).await;
  1022. }
  1023. assert!(!hosts.is_empty_greylist().await);
  1024. let local_hosts = vec![
  1025. (Url::parse("tcp://localhost:3921").unwrap()),
  1026. (Url::parse("tor://[::1]:21481").unwrap()),
  1027. (Url::parse("tcp://192.168.10.65:311").unwrap()),
  1028. (Url::parse("tcp+tls://0.0.0.0:2312").unwrap()),
  1029. (Url::parse("tcp://255.255.255.255:2131").unwrap()),
  1030. ];
  1031. for host in &local_hosts {
  1032. hosts.greylist_store(host.clone(), last_seen).await;
  1033. }
  1034. assert!(!hosts.is_empty_greylist().await);
  1035. let remote_hosts = vec![
  1036. (Url::parse("tcp://dark.fi:80").unwrap()),
  1037. (Url::parse("tcp://http.cat:401").unwrap()),
  1038. (Url::parse("tcp://foo.bar:111").unwrap()),
  1039. ];
  1040. for host in &remote_hosts {
  1041. hosts.greylist_store(host.clone(), last_seen).await;
  1042. }
  1043. assert!(hosts.greylist_contains(&remote_hosts[0]).await);
  1044. assert!(hosts.greylist_contains(&remote_hosts[1]).await);
  1045. assert!(hosts.greylist_contains(&remote_hosts[2]).await);
  1046. });
  1047. }
  1048. #[test]
  1049. fn test_whitelist_store() {
  1050. smol::block_on(async {
  1051. let settings = Settings {
  1052. localnet: false,
  1053. external_addrs: vec![
  1054. Url::parse("tcp://foo.bar:123").unwrap(),
  1055. Url::parse("tcp://lol.cat:321").unwrap(),
  1056. ],
  1057. ..Default::default()
  1058. };
  1059. let hosts = Hosts::new(Arc::new(settings.clone()));
  1060. assert!(hosts.is_empty_whitelist().await);
  1061. let url = Url::parse("tcp://dark.renaissance:333").unwrap();
  1062. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  1063. hosts.whitelist_store(url.clone(), last_seen).await;
  1064. assert!(!hosts.is_empty_whitelist().await);
  1065. assert!(hosts.whitelist_contains(&url).await);
  1066. });
  1067. }
  1068. #[test]
  1069. fn test_whitelist_get_last() {
  1070. smol::block_on(async {
  1071. let settings = Settings {
  1072. localnet: false,
  1073. external_addrs: vec![
  1074. Url::parse("tcp://foo.bar:123").unwrap(),
  1075. Url::parse("tcp://lol.cat:321").unwrap(),
  1076. ],
  1077. ..Default::default()
  1078. };
  1079. let hosts = Hosts::new(Arc::new(settings.clone()));
  1080. // Build up a hostlist
  1081. for i in 0..10 {
  1082. sleep(1).await;
  1083. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  1084. let url = Url::parse(&format!("tcp://whitelist{}:123", i)).unwrap();
  1085. hosts.whitelist_store(url.clone(), last_seen).await;
  1086. }
  1087. for (url, last_seen) in hosts.whitelist.read().await.iter() {
  1088. println!("{} {}", url, last_seen);
  1089. }
  1090. let (entry, _position) = hosts.whitelist_fetch_last().await;
  1091. println!("last entry: {} {}", entry.0, entry.1);
  1092. });
  1093. }
  1094. #[test]
  1095. fn test_hostlist_get_entry() {
  1096. smol::block_on(async {
  1097. let settings = Settings {
  1098. localnet: false,
  1099. external_addrs: vec![
  1100. Url::parse("tcp://foo.bar:123").unwrap(),
  1101. Url::parse("tcp://lol.cat:321").unwrap(),
  1102. ],
  1103. ..Default::default()
  1104. };
  1105. let hosts = Hosts::new(Arc::new(settings.clone()));
  1106. let url = Url::parse("tcp://dark.renaissance:333").unwrap();
  1107. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  1108. hosts.whitelist_store(url.clone(), last_seen).await;
  1109. hosts.anchorlist_store(url.clone(), last_seen).await;
  1110. assert!(hosts.get_whitelist_entry_at_addr(&url).await.is_some());
  1111. assert!(hosts.get_anchorlist_entry_at_addr(&url).await.is_some());
  1112. });
  1113. }
  1114. #[test]
  1115. fn test_remove() {
  1116. smol::block_on(async {
  1117. let settings = Settings {
  1118. outbound_connections: 8,
  1119. allowed_transports: vec!["tcp".to_string()],
  1120. ..Default::default()
  1121. };
  1122. let hosts = Hosts::new(Arc::new(settings.clone()));
  1123. let url = Url::parse("tcp://dark.renaissance:333").unwrap();
  1124. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  1125. hosts.whitelist_store(url.clone(), last_seen).await;
  1126. sleep(1).await;
  1127. let url = Url::parse("tcp://milady:333").unwrap();
  1128. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  1129. hosts.whitelist_store(url.clone(), last_seen).await;
  1130. sleep(1).await;
  1131. let url = Url::parse("tcp://king-ted:333").unwrap();
  1132. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  1133. hosts.whitelist_store(url.clone(), last_seen).await;
  1134. for (url, last_seen) in hosts.whitelist.read().await.iter() {
  1135. println!("{}, {}", url, last_seen);
  1136. }
  1137. let position = hosts.get_whitelist_index_at_addr(url.clone()).await.unwrap();
  1138. hosts.whitelist_remove(&url, position).await;
  1139. for (url, last_seen) in hosts.whitelist.read().await.iter() {
  1140. println!("{}, {}", url, last_seen);
  1141. }
  1142. });
  1143. }
  1144. #[test]
  1145. fn test_fetch_address() {
  1146. smol::block_on(async {
  1147. let mut hostlist = vec![];
  1148. let mut grey_urls = vec![];
  1149. let mut white_urls = vec![];
  1150. let mut anchor_urls = vec![];
  1151. let ex = Arc::new(Executor::new());
  1152. let settings = Settings {
  1153. outbound_connections: 8,
  1154. allowed_transports: vec!["tcp".to_string()],
  1155. ..Default::default()
  1156. };
  1157. let p2p = P2p::new(settings, ex.clone()).await;
  1158. let hosts = p2p.hosts();
  1159. // Build up a hostlist
  1160. for i in 0..5 {
  1161. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  1162. hosts
  1163. .anchorlist_store(
  1164. Url::parse(&format!("tcp://anchorlist{}:123", i)).unwrap(),
  1165. last_seen,
  1166. )
  1167. .await;
  1168. hosts
  1169. .whitelist_store(
  1170. Url::parse(&format!("tcp://whitelist{}:123", i)).unwrap(),
  1171. last_seen,
  1172. )
  1173. .await;
  1174. hosts
  1175. .greylist_store(
  1176. Url::parse(&format!("tcp://greylist{}:123", i)).unwrap(),
  1177. last_seen,
  1178. )
  1179. .await;
  1180. grey_urls
  1181. .push((Url::parse(&format!("tcp://greylist{}:123", i)).unwrap(), last_seen));
  1182. white_urls
  1183. .push((Url::parse(&format!("tcp://whitelist{}:123", i)).unwrap(), last_seen));
  1184. anchor_urls
  1185. .push((Url::parse(&format!("tcp://anchorlist{}:123", i)).unwrap(), last_seen));
  1186. }
  1187. assert!(!hosts.is_empty_anchorlist().await);
  1188. assert!(!hosts.is_empty_whitelist().await);
  1189. assert!(!hosts.is_empty_greylist().await);
  1190. let transports = &p2p.settings().allowed_transports;
  1191. let white_count =
  1192. p2p.settings().outbound_connections * p2p.settings().white_connection_percent / 100;
  1193. // Simulate the address selection logic found in outbound_session::fetch_address()
  1194. for i in 0..8 {
  1195. let addrs = {
  1196. if i < p2p.settings().anchor_connection_count {
  1197. hosts.anchorlist_fetch_address(transports).await
  1198. } else if i < white_count {
  1199. hosts.whitelist_fetch_address(transports).await
  1200. } else {
  1201. hosts.greylist_fetch_address(transports).await
  1202. }
  1203. };
  1204. hostlist.push(addrs);
  1205. }
  1206. //// Check we're returning the correct addresses.
  1207. anchor_urls.sort();
  1208. white_urls.sort();
  1209. grey_urls.sort();
  1210. hostlist[0].sort();
  1211. hostlist[4].sort();
  1212. hostlist[7].sort();
  1213. assert!(anchor_urls == hostlist[0]);
  1214. assert!(white_urls == hostlist[4]);
  1215. assert!(grey_urls == hostlist[7]);
  1216. // Now clear the anchorlist.
  1217. // anchorlist_fetch_address should return whitelist entries if
  1218. // the anchorlist is empty.
  1219. let mut anchorlist = hosts.anchorlist.write().await;
  1220. anchorlist.clear();
  1221. drop(anchorlist);
  1222. let mut addrs = hosts.anchorlist_fetch_address(transports).await;
  1223. addrs.sort();
  1224. assert!(white_urls == addrs);
  1225. // Now clear the whitelist.
  1226. // anchorlist_fetch_address should return greylist entries if
  1227. // both the anchorlist and the whitelist are empty.
  1228. let mut whitelist = hosts.whitelist.write().await;
  1229. whitelist.clear();
  1230. drop(whitelist);
  1231. let mut addrs = hosts.anchorlist_fetch_address(transports).await;
  1232. addrs.sort();
  1233. assert!(grey_urls == addrs);
  1234. })
  1235. }
  1236. }