protocol_address.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 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 async_trait::async_trait;
  19. use smol::{lock::RwLock as AsyncRwLock, Executor};
  20. use std::{sync::Arc, time::UNIX_EPOCH};
  21. use tracing::debug;
  22. use url::Url;
  23. use super::{
  24. super::{
  25. channel::ChannelPtr,
  26. hosts::{HostColor, HostsPtr},
  27. message::{AddrsMessage, GetAddrsMessage},
  28. message_publisher::MessageSubscription,
  29. p2p::P2pPtr,
  30. session::SESSION_OUTBOUND,
  31. settings::Settings,
  32. },
  33. protocol_base::{ProtocolBase, ProtocolBasePtr},
  34. protocol_jobs_manager::{ProtocolJobsManager, ProtocolJobsManagerPtr},
  35. };
  36. use crate::Result;
  37. /// Defines address and get-address messages.
  38. ///
  39. /// On receiving GetAddr, nodes reply an AddrMessage containing nodes from
  40. /// their hostlist. On receiving an AddrMessage, nodes enter the info into
  41. /// their greylists.
  42. ///
  43. /// The node selection logic for creating an AddrMessage is as follows:
  44. ///
  45. /// 1. First select nodes matching the requested transports from the
  46. /// anchorlist. These nodes have the highest guarantee of being reachable,
  47. /// so we prioritize them first.
  48. ///
  49. /// 2. Then select nodes matching the requested transports from the
  50. /// whitelist.
  51. ///
  52. /// 3. Next select whitelist nodes that don't match our transports. We do
  53. /// this so that nodes share and propagate nodes of different transports,
  54. /// even if they can't connect to them themselves.
  55. ///
  56. /// 4. Finally, if there's still space available, fill the remaining vector
  57. /// space with darklist entries. This is necessary to propagate transports
  58. /// that neither this node nor the receiving node support.
  59. pub struct ProtocolAddress {
  60. channel: ChannelPtr,
  61. addrs_sub: MessageSubscription<AddrsMessage>,
  62. get_addrs_sub: MessageSubscription<GetAddrsMessage>,
  63. hosts: HostsPtr,
  64. settings: Arc<AsyncRwLock<Settings>>,
  65. jobsman: ProtocolJobsManagerPtr,
  66. }
  67. const PROTO_NAME: &str = "ProtocolAddress";
  68. /// A vector of all currently accepted transports and valid transport
  69. /// combinations. Should be updated if and when new transports are
  70. /// added. Creates a upper bound on the number of transports a given peer
  71. /// can request.
  72. const TRANSPORT_COMBOS: [&str; 9] =
  73. ["tor", "tls", "tcp", "nym", "i2p", "tor+tls", "nym+tls", "tcp+tls", "i2p+tls"];
  74. /// Strip query parameters from a URL before broadcasting.
  75. ///
  76. /// This prevents leaking internal tracking identifiers (e.g., UPnP cookies)
  77. /// that could be used for fingerprinting nodes on the P2P network.
  78. fn strip_query_params(url: &Url) -> Url {
  79. let mut stripped = url.clone();
  80. stripped.set_query(None);
  81. stripped
  82. }
  83. impl ProtocolAddress {
  84. /// Creates a new address protocol. Makes an address, an external address
  85. /// and a get-address subscription and adds them to the address protocol
  86. /// instance.
  87. pub async fn init(channel: ChannelPtr, p2p: P2pPtr) -> ProtocolBasePtr {
  88. // Creates a subscription to address message
  89. let addrs_sub =
  90. channel.subscribe_msg::<AddrsMessage>().await.expect("Missing addrs dispatcher!");
  91. // Creates a subscription to get-address message
  92. let get_addrs_sub =
  93. channel.subscribe_msg::<GetAddrsMessage>().await.expect("Missing getaddrs dispatcher!");
  94. Arc::new(Self {
  95. channel: channel.clone(),
  96. addrs_sub,
  97. get_addrs_sub,
  98. hosts: p2p.hosts(),
  99. jobsman: ProtocolJobsManager::new(PROTO_NAME, channel),
  100. settings: p2p.settings(),
  101. })
  102. }
  103. /// Handles receiving the address message. Loops to continually receive
  104. /// address messages on the address subscription. Validates and adds the
  105. /// received addresses to the greylist.
  106. async fn handle_receive_addrs(self: Arc<Self>) -> Result<()> {
  107. debug!(
  108. target: "net::protocol_address::handle_receive_addrs",
  109. "[START] address={}", self.channel.display_address(),
  110. );
  111. loop {
  112. let addrs_msg = self.addrs_sub.receive().await?;
  113. debug!(
  114. target: "net::protocol_address::handle_receive_addrs",
  115. "Received {} addrs from {}", addrs_msg.addrs.len(), self.channel.display_address(),
  116. );
  117. debug!(
  118. target: "net::protocol_address::handle_receive_addrs",
  119. "Appending to greylist...",
  120. );
  121. self.hosts.insert(HostColor::Grey, &addrs_msg.addrs).await;
  122. }
  123. }
  124. /// Handles receiving the get-address message. Continually receives
  125. /// get-address messages on the get-address subscription. Then replies
  126. /// with an address message.
  127. async fn handle_receive_get_addrs(self: Arc<Self>) -> Result<()> {
  128. debug!(
  129. target: "net::protocol_address::handle_receive_get_addrs",
  130. "[START] address={}", self.channel.display_address(),
  131. );
  132. loop {
  133. let get_addrs_msg = self.get_addrs_sub.receive().await?;
  134. debug!(
  135. target: "net::protocol_address::handle_receive_get_addrs",
  136. "Received GetAddrs({}) message from {}", get_addrs_msg.max, self.channel.display_address(),
  137. );
  138. // Filter out transports not meant to be shared like Socks5 and Socks5+tls
  139. let requested_transports: Vec<String> = get_addrs_msg
  140. .transports
  141. .iter()
  142. .filter(|tp| TRANSPORT_COMBOS.contains(&tp.as_str()))
  143. .cloned()
  144. .collect();
  145. // First we grab address with the requested transports from the gold list
  146. debug!(target: "net::protocol_address::handle_receive_get_addrs",
  147. "Fetching gold entries with schemes");
  148. let mut addrs = self.hosts.container.fetch_n_random_with_schemes(
  149. HostColor::Gold,
  150. &requested_transports,
  151. get_addrs_msg.max as usize,
  152. );
  153. // Then we grab address with the requested transports from the whitelist
  154. debug!(target: "net::protocol_address::handle_receive_get_addrs",
  155. "Fetching whitelist entries with schemes");
  156. addrs.append(&mut self.hosts.container.fetch_n_random_with_schemes(
  157. HostColor::White,
  158. &requested_transports,
  159. get_addrs_msg.max as usize,
  160. ));
  161. // Next we grab addresses without the requested transports
  162. // to fill a 2 * max length vector.
  163. // Then we grab address without the requested transports from the gold list
  164. debug!(target: "net::protocol_address::handle_receive_get_addrs",
  165. "Fetching gold entries without schemes");
  166. let remain = 2 * get_addrs_msg.max as usize - addrs.len();
  167. addrs.append(&mut self.hosts.container.fetch_n_random_excluding_schemes(
  168. HostColor::Gold,
  169. &requested_transports,
  170. remain,
  171. ));
  172. // Then we grab address without the requested transports from the white list
  173. debug!(target: "net::protocol_address::handle_receive_get_addrs",
  174. "Fetching white entries without schemes");
  175. let remain = 2 * get_addrs_msg.max as usize - addrs.len();
  176. addrs.append(&mut self.hosts.container.fetch_n_random_excluding_schemes(
  177. HostColor::White,
  178. &requested_transports,
  179. remain,
  180. ));
  181. // If there's still space available, take from the Dark list.
  182. /* NOTE: We share peers from our Dark list because to ensure
  183. that non-compatiable transports are shared with other nodes
  184. so that they propagate on the network even if they're not
  185. popular transports. */
  186. debug!(target: "net::protocol_address::handle_receive_get_addrs",
  187. "Fetching dark entries");
  188. let remain = 2 * get_addrs_msg.max as usize - addrs.len();
  189. addrs.append(&mut self.hosts.container.fetch_n_random(HostColor::Dark, remain));
  190. // Filter out transports not meant to be shared like Socks5 and Socks5+tls
  191. addrs.retain(|addr| TRANSPORT_COMBOS.contains(&addr.0.scheme()));
  192. debug!(
  193. target: "net::protocol_address::handle_receive_get_addrs",
  194. "Sending {} addresses to {}", addrs.len(), self.channel.display_address(),
  195. );
  196. let addrs_msg = AddrsMessage { addrs };
  197. self.channel.send(&addrs_msg).await?;
  198. }
  199. }
  200. /// Send our own external addresses over a channel. Set the
  201. /// last_seen field to now.
  202. async fn send_my_addrs(self: Arc<Self>) -> Result<()> {
  203. debug!(
  204. target: "net::protocol_address::send_my_addrs",
  205. "[START] channel address={}", self.channel.display_address(),
  206. );
  207. if self.channel.session_type_id() != SESSION_OUTBOUND {
  208. debug!(
  209. target: "net::protocol_address::send_my_addrs",
  210. "Not an outbound session. Stopping",
  211. );
  212. return Ok(())
  213. }
  214. let external_addrs = self.channel.hosts().external_addrs().await;
  215. if external_addrs.is_empty() {
  216. debug!(
  217. target: "net::protocol_address::send_my_addrs",
  218. "External addr not configured. Stopping",
  219. );
  220. return Ok(())
  221. }
  222. let mut addrs = vec![];
  223. for addr in external_addrs {
  224. let stripped_addr = strip_query_params(&addr);
  225. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  226. addrs.push((stripped_addr, last_seen));
  227. }
  228. debug!(
  229. target: "net::protocol_address::send_my_addrs",
  230. "Broadcasting {} addresses", addrs.len(),
  231. );
  232. let ext_addr_msg = AddrsMessage { addrs };
  233. self.channel.send(&ext_addr_msg).await?;
  234. debug!(
  235. target: "net::protocol_address::send_my_addrs",
  236. "[END] channel address={}", self.channel.display_address(),
  237. );
  238. Ok(())
  239. }
  240. }
  241. #[async_trait]
  242. impl ProtocolBase for ProtocolAddress {
  243. /// Start the address protocol. If it's an outbound session and has an
  244. /// external address, send our external address. Run receive address
  245. /// and get address protocols on the protocol task manager. Then send
  246. /// get-address msg.
  247. async fn start(self: Arc<Self>, ex: Arc<Executor<'_>>) -> Result<()> {
  248. debug!(
  249. target: "net::protocol_address::start",
  250. "START => address={}", self.channel.display_address(),
  251. );
  252. let settings = self.settings.read().await;
  253. let outbound_connections = settings.outbound_connections;
  254. let active_profiles = settings.active_profiles.clone();
  255. let getaddrs_max = settings.getaddrs_max;
  256. drop(settings);
  257. self.jobsman.clone().start(ex.clone());
  258. self.jobsman.clone().spawn(self.clone().send_my_addrs(), ex.clone()).await;
  259. self.jobsman.clone().spawn(self.clone().handle_receive_addrs(), ex.clone()).await;
  260. self.jobsman.spawn(self.clone().handle_receive_get_addrs(), ex).await;
  261. // Send get_address message.
  262. // We ask for a maximum of u8::MAX addresses from a single node
  263. let get_addrs = GetAddrsMessage {
  264. max: getaddrs_max.unwrap_or(outbound_connections.min(u32::MAX as usize) as u32),
  265. transports: active_profiles,
  266. };
  267. self.channel.send(&get_addrs).await?;
  268. debug!(
  269. target: "net::protocol_address::start",
  270. "END => address={}", self.channel.display_address(),
  271. );
  272. Ok(())
  273. }
  274. fn name(&self) -> &'static str {
  275. PROTO_NAME
  276. }
  277. }
  278. #[cfg(test)]
  279. mod tests {
  280. use darkfi_serial::serialize;
  281. use crate::net::message::GET_ADDRS_MAX_BYTES;
  282. use super::{GetAddrsMessage, TRANSPORT_COMBOS};
  283. // Helps to check if the MAX_BYTES for GetAddrs message is valid as new transports are added
  284. #[test]
  285. fn test_get_addrs_msg_size() {
  286. let message = GetAddrsMessage {
  287. max: u8::MAX as u32,
  288. transports: TRANSPORT_COMBOS.iter().map(|x| x.to_string()).collect(),
  289. };
  290. assert_eq!(serialize(&message).len() as u64, GET_ADDRS_MAX_BYTES);
  291. }
  292. }