radicle/node/
address.rs

1pub mod store;
2pub use store::{Error, Store};
3
4use std::cell::RefCell;
5use std::ops::{Deref, DerefMut};
6use std::{hash, net};
7
8use cyphernet::addr::HostName;
9use localtime::LocalTime;
10use nonempty::NonEmpty;
11
12use crate::collections::RandomMap;
13use crate::node::{Address, Alias, Penalty, UserAgent};
14use crate::prelude::Timestamp;
15use crate::{node, profile};
16
17/// A map with the ability to randomly select values.
18#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
19#[serde(transparent)]
20pub struct AddressBook<K: hash::Hash + Eq, V> {
21    inner: RandomMap<K, V>,
22    #[serde(skip)]
23    rng: RefCell<fastrand::Rng>,
24}
25
26impl<K: hash::Hash + Eq, V> AddressBook<K, V> {
27    /// Create a new address book.
28    pub fn new(rng: fastrand::Rng) -> Self {
29        Self {
30            inner: RandomMap::with_hasher(rng.clone().into()),
31            rng: RefCell::new(rng),
32        }
33    }
34
35    /// Pick a random value in the book.
36    pub fn sample(&self) -> Option<(&K, &V)> {
37        self.sample_with(|_, _| true)
38    }
39
40    /// Pick a random value in the book matching a predicate.
41    pub fn sample_with(&self, mut predicate: impl FnMut(&K, &V) -> bool) -> Option<(&K, &V)> {
42        if let Some(pairs) = NonEmpty::from_vec(
43            self.inner
44                .iter()
45                .filter(|(k, v)| predicate(*k, *v))
46                .collect(),
47        ) {
48            let ix = self.rng.borrow_mut().usize(..pairs.len());
49            let pair = pairs[ix]; // Can't fail.
50
51            Some(pair)
52        } else {
53            None
54        }
55    }
56
57    /// Return a new address book with the given RNG.
58    pub fn with(self, rng: fastrand::Rng) -> Self {
59        Self {
60            inner: self.inner,
61            rng: RefCell::new(rng),
62        }
63    }
64}
65
66impl<K: hash::Hash + Eq + Ord + Copy, V> AddressBook<K, V> {
67    /// Return a shuffled iterator.
68    pub fn shuffled(&self) -> std::vec::IntoIter<(&K, &V)> {
69        let mut items = self.inner.iter().collect::<Vec<_>>();
70        items.sort_by_key(|(k, _)| *k);
71        self.rng.borrow_mut().shuffle(&mut items);
72
73        items.into_iter()
74    }
75
76    /// Turn this object into a shuffled iterator.
77    pub fn into_shuffled(self) -> impl Iterator<Item = (K, V)> {
78        let mut items = self.inner.into_iter().collect::<Vec<_>>();
79        items.sort_by_key(|(k, _)| *k);
80        self.rng.borrow_mut().shuffle(&mut items);
81
82        items.into_iter()
83    }
84
85    /// Cycle through the keys at random. The random cycle repeats ad-infintum.
86    pub fn cycle(&self) -> impl Iterator<Item = &K> {
87        self.shuffled().map(|(k, _)| k).cycle()
88    }
89}
90
91impl<K: hash::Hash + Eq, V> FromIterator<(K, V)> for AddressBook<K, V> {
92    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
93        let rng = profile::env::rng();
94        let mut inner = RandomMap::with_hasher(rng.clone().into());
95
96        for (k, v) in iter {
97            inner.insert(k, v);
98        }
99        Self {
100            inner,
101            rng: RefCell::new(rng),
102        }
103    }
104}
105
106impl<K: hash::Hash + Eq, V> Deref for AddressBook<K, V> {
107    type Target = RandomMap<K, V>;
108
109    fn deref(&self) -> &Self::Target {
110        &self.inner
111    }
112}
113
114impl<K: hash::Hash + Eq, V> DerefMut for AddressBook<K, V> {
115    fn deref_mut(&mut self) -> &mut Self::Target {
116        &mut self.inner
117    }
118}
119
120/// Node public data.
121#[derive(Debug, Clone, PartialEq, Eq)]
122pub struct Node {
123    /// Protocol version.
124    pub version: u8,
125    /// Advertized alias.
126    pub alias: Alias,
127    /// Advertized features.
128    pub features: node::Features,
129    /// Advertized addresses
130    pub addrs: Vec<KnownAddress>,
131    /// Proof-of-work included in node announcement.
132    pub pow: u32,
133    /// When this data was published.
134    pub timestamp: Timestamp,
135    /// User agent string.
136    pub agent: UserAgent,
137    /// Node connection penalty.
138    pub penalty: Penalty,
139    /// Whether the node is banned.
140    pub banned: bool,
141}
142
143/// A known address.
144#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
145#[serde(rename_all = "camelCase")]
146pub struct KnownAddress {
147    /// Network address.
148    pub addr: Address,
149    /// Address of the peer who sent us this address.
150    pub source: Source,
151    /// Last time this address was used to successfully connect to a peer.
152    #[serde(with = "crate::serde_ext::localtime::option::time")]
153    pub last_success: Option<LocalTime>,
154    /// Last time this address was tried.
155    #[serde(with = "crate::serde_ext::localtime::option::time")]
156    pub last_attempt: Option<LocalTime>,
157    /// Whether this address has been banned.
158    pub banned: bool,
159}
160
161impl KnownAddress {
162    /// Create a new known address.
163    pub fn new(addr: Address, source: Source) -> Self {
164        Self {
165            addr,
166            source,
167            last_success: None,
168            last_attempt: None,
169            banned: false,
170        }
171    }
172}
173
174/// Address source. Specifies where an address originated from.
175#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
176#[serde(rename_all = "camelCase")]
177pub enum Source {
178    /// An address that was shared by another peer.
179    Peer,
180    /// A bootstrap node address.
181    Bootstrap,
182    /// An address that came from some source external to the system, eg.
183    /// specified by the user or added directly to the address manager.
184    Imported,
185}
186
187impl std::fmt::Display for Source {
188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189        match self {
190            Self::Peer => write!(f, "Peer"),
191            Self::Bootstrap => write!(f, "Bootstrap"),
192            Self::Imported => write!(f, "Imported"),
193        }
194    }
195}
196
197/// Address type.
198#[repr(u8)]
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
200pub enum AddressType {
201    Ipv4 = 1,
202    Ipv6 = 2,
203    Dns = 3,
204    Onion = 4,
205}
206
207impl From<AddressType> for u8 {
208    fn from(other: AddressType) -> Self {
209        other as u8
210    }
211}
212
213impl From<&Address> for AddressType {
214    fn from(a: &Address) -> Self {
215        match a.host {
216            HostName::Ip(net::IpAddr::V4(_)) => AddressType::Ipv4,
217            HostName::Ip(net::IpAddr::V6(_)) => AddressType::Ipv6,
218            HostName::Dns(_) => AddressType::Dns,
219            HostName::Tor(_) => AddressType::Onion,
220            _ => todo!(), // FIXME(cloudhead): Maxim will remove `non-exhaustive`
221        }
222    }
223}
224
225impl TryFrom<u8> for AddressType {
226    type Error = u8;
227
228    fn try_from(other: u8) -> Result<Self, Self::Error> {
229        match other {
230            1 => Ok(AddressType::Ipv4),
231            2 => Ok(AddressType::Ipv6),
232            3 => Ok(AddressType::Dns),
233            4 => Ok(AddressType::Onion),
234            _ => Err(other),
235        }
236    }
237}
238/// Check whether an IP address is globally routable.
239pub fn is_routable(addr: &net::IpAddr) -> bool {
240    match addr {
241        net::IpAddr::V4(addr) => ipv4_is_routable(addr),
242        net::IpAddr::V6(addr) => ipv6_is_routable(addr),
243    }
244}
245
246/// Check whether an IP address is locally routable.
247pub fn is_local(addr: &net::IpAddr) -> bool {
248    match addr {
249        net::IpAddr::V4(addr) => {
250            addr.is_private() || addr.is_loopback() || addr.is_link_local() || addr.is_unspecified()
251        }
252        net::IpAddr::V6(_) => false,
253    }
254}
255
256/// Check whether an IPv4 address is globally routable.
257///
258/// This code is adapted from the Rust standard library's `net::Ipv4Addr::is_global`. It can be
259/// replaced once that function is stabilized.
260fn ipv4_is_routable(addr: &net::Ipv4Addr) -> bool {
261    // Check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
262    // globally routable addresses in the 192.0.0.0/24 range.
263    if u32::from(*addr) == 0xc0000009 || u32::from(*addr) == 0xc000000a {
264        return true;
265    }
266    !addr.is_private()
267        && !addr.is_loopback()
268        && !addr.is_link_local()
269        && !addr.is_broadcast()
270        && !addr.is_documentation()
271        // Make sure the address is not in 0.0.0.0/8.
272        && addr.octets()[0] != 0
273}
274
275/// Check whether an IPv6 address is globally routable.
276///
277/// For now, this always returns `true`, as IPv6 addresses
278/// are not fully supported.
279fn ipv6_is_routable(_addr: &net::Ipv6Addr) -> bool {
280    true
281}