pub mod store; pub use store::{Error, Store}; use std::cell::RefCell; use std::ops::{Deref, DerefMut}; use std::{hash, net}; use cyphernet::addr::HostName; use localtime::LocalTime; use nonempty::NonEmpty; use crate::collections::RandomMap; use crate::node::{Address, Alias, Penalty, UserAgent}; use crate::prelude::Timestamp; use crate::{node, profile}; /// A map with the ability to randomly select values. #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(transparent)] pub struct AddressBook { inner: RandomMap, #[serde(skip)] rng: RefCell, } impl AddressBook { /// Create a new address book. pub fn new(rng: fastrand::Rng) -> Self { Self { inner: RandomMap::with_hasher(rng.clone().into()), rng: RefCell::new(rng), } } /// Pick a random value in the book. pub fn sample(&self) -> Option<(&K, &V)> { self.sample_with(|_, _| true) } /// Pick a random value in the book matching a predicate. pub fn sample_with(&self, mut predicate: impl FnMut(&K, &V) -> bool) -> Option<(&K, &V)> { if let Some(pairs) = NonEmpty::from_vec( self.inner .iter() .filter(|(k, v)| predicate(*k, *v)) .collect(), ) { let ix = self.rng.borrow_mut().usize(..pairs.len()); let pair = pairs[ix]; // Can't fail. Some(pair) } else { None } } /// Return a new address book with the given RNG. pub fn with(self, rng: fastrand::Rng) -> Self { Self { inner: self.inner, rng: RefCell::new(rng), } } } impl AddressBook { /// Return a shuffled iterator. pub fn shuffled(&self) -> std::vec::IntoIter<(&K, &V)> { let mut items = self.inner.iter().collect::>(); items.sort_by_key(|(k, _)| *k); self.rng.borrow_mut().shuffle(&mut items); items.into_iter() } /// Turn this object into a shuffled iterator. pub fn into_shuffled(self) -> impl Iterator { let mut items = self.inner.into_iter().collect::>(); items.sort_by_key(|(k, _)| *k); self.rng.borrow_mut().shuffle(&mut items); items.into_iter() } /// Cycle through the keys at random. The random cycle repeats ad-infintum. pub fn cycle(&self) -> impl Iterator { self.shuffled().map(|(k, _)| k).cycle() } } impl FromIterator<(K, V)> for AddressBook { fn from_iter>(iter: T) -> Self { let rng = profile::env::rng(); let mut inner = RandomMap::with_hasher(rng.clone().into()); for (k, v) in iter { inner.insert(k, v); } Self { inner, rng: RefCell::new(rng), } } } impl Deref for AddressBook { type Target = RandomMap; fn deref(&self) -> &Self::Target { &self.inner } } impl DerefMut for AddressBook { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } /// Node public data. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Node { /// Protocol version. pub version: u8, /// Advertised alias. pub alias: Alias, /// Advertised features. pub features: node::Features, /// Advertised addresses pub addrs: Vec, /// Proof-of-work included in node announcement. pub pow: u32, /// When this data was published. pub timestamp: Timestamp, /// User agent string. pub agent: UserAgent, /// Node connection penalty. pub penalty: Penalty, /// Whether the node is banned. pub banned: bool, } /// A known address. #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct KnownAddress { /// Network address. pub addr: Address, /// Address of the peer who sent us this address. pub source: Source, /// Last time this address was used to successfully connect to a peer. pub last_success: Option, /// Last time this address was tried. pub last_attempt: Option, /// Whether this address has been banned. pub banned: bool, } impl KnownAddress { /// Create a new known address. pub fn new(addr: Address, source: Source) -> Self { Self { addr, source, last_success: None, last_attempt: None, banned: false, } } } /// Address source. Specifies where an address originated from. #[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum Source { /// An address that was shared by another peer. Peer, /// A bootstrap node address. Bootstrap, /// An address that came from some source external to the system, eg. /// specified by the user or added directly to the address manager. Imported, } impl std::fmt::Display for Source { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Peer => write!(f, "Peer"), Self::Bootstrap => write!(f, "Bootstrap"), Self::Imported => write!(f, "Imported"), } } } /// Address type. #[repr(u8)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AddressType { Ipv4 = 1, Ipv6 = 2, Dns = 3, #[cfg(feature = "tor")] Onion = 4, } impl From for u8 { fn from(other: AddressType) -> Self { other as u8 } } impl From<&Address> for AddressType { fn from(a: &Address) -> Self { match a.host { HostName::Ip(net::IpAddr::V4(_)) => AddressType::Ipv4, HostName::Ip(net::IpAddr::V6(_)) => AddressType::Ipv6, HostName::Dns(_) => AddressType::Dns, #[cfg(feature = "tor")] HostName::Tor(_) => AddressType::Onion, _ => todo!(), // FIXME(cloudhead): Maxim will remove `non-exhaustive` } } } impl TryFrom for AddressType { type Error = u8; fn try_from(other: u8) -> Result { match other { 1 => Ok(AddressType::Ipv4), 2 => Ok(AddressType::Ipv6), 3 => Ok(AddressType::Dns), #[cfg(feature = "tor")] 4 => Ok(AddressType::Onion), _ => Err(other), } } } /// Check whether an IP address is globally routable. pub fn is_routable(addr: &net::IpAddr) -> bool { match addr { net::IpAddr::V4(addr) => ipv4_is_routable(addr), net::IpAddr::V6(addr) => ipv6_is_routable(addr), } } /// Check whether an IP address is locally routable. pub fn is_local(addr: &net::IpAddr) -> bool { match addr { net::IpAddr::V4(addr) => { addr.is_private() || addr.is_loopback() || addr.is_link_local() || addr.is_unspecified() } net::IpAddr::V6(addr) => { addr.is_loopback() || addr.is_unicast_link_local() || addr.is_unspecified() } } } /// Check whether an IPv4 address is globally routable. /// /// This implementation lacks many exceptions, and should be improved once /// corresponding functions in [`std::net::Ipv4Addr`] are stabilized. /// /// See /// - /// - fn ipv4_is_routable(addr: &net::Ipv4Addr) -> bool { // https://datatracker.ietf.org/doc/html/rfc7723#section-4.1 if *addr == net::Ipv4Addr::new(192, 0, 0, 9) { return true; } // https://datatracker.ietf.org/doc/html/rfc8155#section-8.1 if *addr == net::Ipv4Addr::new(192, 0, 0, 10) { return true; } // https://datatracker.ietf.org/doc/html/rfc791#section-3.2 if addr.octets()[0] == 0 { return false; } !addr.is_private() && !addr.is_loopback() && !addr.is_link_local() && !addr.is_broadcast() && !addr.is_documentation() } /// Check whether an IPv6 address is globally routable. /// /// This implementation lacks many exceptions, and should be improved once /// corresponding functions in [`std::net::Ipv6Addr`] are stabilized. /// /// See /// - /// - fn ipv6_is_routable(addr: &net::Ipv6Addr) -> bool { !addr.is_loopback() && !addr.is_unicast_link_local() && !addr.is_unspecified() }