protocol_address.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 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 log::debug;
  20. use smol::{lock::RwLock as AsyncRwLock, Executor};
  21. use std::{sync::Arc, time::UNIX_EPOCH};
  22. use url::{Host, Url};
  23. use super::{
  24. super::{
  25. channel::{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::{Error, 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; 7] = ["tor", "tls", "tcp", "nym", "tor+tls", "nym+tls", "tcp+tls"];
  73. impl ProtocolAddress {
  74. /// Creates a new address protocol. Makes an address, an external address
  75. /// and a get-address subscription and adds them to the address protocol
  76. /// instance.
  77. pub async fn init(channel: ChannelPtr, p2p: P2pPtr) -> ProtocolBasePtr {
  78. // Creates a subscription to address message
  79. let addrs_sub =
  80. channel.subscribe_msg::<AddrsMessage>().await.expect("Missing addrs dispatcher!");
  81. // Creates a subscription to get-address message
  82. let get_addrs_sub =
  83. channel.subscribe_msg::<GetAddrsMessage>().await.expect("Missing getaddrs dispatcher!");
  84. Arc::new(Self {
  85. channel: channel.clone(),
  86. addrs_sub,
  87. get_addrs_sub,
  88. hosts: p2p.hosts(),
  89. jobsman: ProtocolJobsManager::new(PROTO_NAME, channel),
  90. settings: p2p.settings(),
  91. })
  92. }
  93. /// Handles receiving the address message. Loops to continually receive
  94. /// address messages on the address subscription. Validates and adds the
  95. /// received addresses to the greylist.
  96. async fn handle_receive_addrs(self: Arc<Self>) -> Result<()> {
  97. debug!(
  98. target: "net::protocol_address::handle_receive_addrs()",
  99. "[START] address={}", self.channel.address(),
  100. );
  101. loop {
  102. let addrs_msg = self.addrs_sub.receive().await?;
  103. debug!(
  104. target: "net::protocol_address::handle_receive_addrs()",
  105. "Received {} addrs from {}", addrs_msg.addrs.len(), self.channel.address(),
  106. );
  107. debug!(
  108. target: "net::protocol_address::handle_receive_addrs()",
  109. "Appending to greylist...",
  110. );
  111. self.hosts.insert(HostColor::Grey, &addrs_msg.addrs).await;
  112. }
  113. }
  114. /// Handles receiving the get-address message. Continually receives
  115. /// get-address messages on the get-address subscription. Then replies
  116. /// with an address message.
  117. async fn handle_receive_get_addrs(self: Arc<Self>) -> Result<()> {
  118. debug!(
  119. target: "net::protocol_address::handle_receive_get_addrs()",
  120. "[START] address={}", self.channel.address(),
  121. );
  122. loop {
  123. let get_addrs_msg = self.get_addrs_sub.receive().await?;
  124. debug!(
  125. target: "net::protocol_address::handle_receive_get_addrs()",
  126. "Received GetAddrs({}) message from {}", get_addrs_msg.max, self.channel.address(),
  127. );
  128. // Check that this peer isn't requesting more transports than we support
  129. // (the max number of all transports, plus mixing).
  130. if get_addrs_msg.transports.len() > TRANSPORT_COMBOS.len() {
  131. return Err(Error::InvalidTransportRequest);
  132. }
  133. // First we grab address with the requested transports from the gold list
  134. debug!(target: "net::protocol_address::handle_receive_get_addrs()",
  135. "Fetching gold entries with schemes");
  136. let mut addrs = self.hosts.container.fetch_n_random_with_schemes(
  137. HostColor::Gold,
  138. &get_addrs_msg.transports,
  139. get_addrs_msg.max,
  140. );
  141. // Then we grab address with the requested transports from the whitelist
  142. debug!(target: "net::protocol_address::handle_receive_get_addrs()",
  143. "Fetching whitelist entries with schemes");
  144. addrs.append(&mut self.hosts.container.fetch_n_random_with_schemes(
  145. HostColor::White,
  146. &get_addrs_msg.transports,
  147. get_addrs_msg.max,
  148. ));
  149. // Next we grab addresses without the requested transports
  150. // to fill a 2 * max length vector.
  151. // Then we grab address without the requested transports from the gold list
  152. debug!(target: "net::protocol_address::handle_receive_get_addrs()",
  153. "Fetching gold entries without schemes");
  154. let remain = 2 * get_addrs_msg.max - addrs.len() as u32;
  155. addrs.append(&mut self.hosts.container.fetch_n_random_excluding_schemes(
  156. HostColor::Gold,
  157. &get_addrs_msg.transports,
  158. remain,
  159. ));
  160. // Then we grab address without the requested transports from the white list
  161. debug!(target: "net::protocol_address::handle_receive_get_addrs()",
  162. "Fetching white entries without schemes");
  163. let remain = 2 * get_addrs_msg.max - addrs.len() as u32;
  164. addrs.append(&mut self.hosts.container.fetch_n_random_excluding_schemes(
  165. HostColor::White,
  166. &get_addrs_msg.transports,
  167. remain,
  168. ));
  169. // If there's still space available, take from the Dark list.
  170. /* NOTE: We share peers from our Dark list because to ensure
  171. that non-compatiable transports are shared with other nodes
  172. so that they propagate on the network even if they're not
  173. popular transports. */
  174. debug!(target: "net::protocol_address::handle_receive_get_addrs()",
  175. "Fetching dark entries");
  176. let remain = 2 * get_addrs_msg.max - addrs.len() as u32;
  177. addrs.append(&mut self.hosts.container.fetch_n_random(HostColor::Dark, remain));
  178. debug!(
  179. target: "net::protocol_address::handle_receive_get_addrs()",
  180. "Sending {} addresses to {}", addrs.len(), self.channel.address(),
  181. );
  182. let addrs_msg = AddrsMessage { addrs };
  183. self.channel.send(&addrs_msg).await?;
  184. }
  185. }
  186. /// Send our own external addresses over a channel. Set the
  187. /// last_seen field to now.
  188. async fn send_my_addrs(self: Arc<Self>) -> Result<()> {
  189. debug!(
  190. target: "net::protocol_address::send_my_addrs",
  191. "[START] channel address={}", self.channel.address(),
  192. );
  193. if self.channel.session_type_id() != SESSION_OUTBOUND {
  194. debug!(
  195. target: "net::protocol_address::send_my_addrs",
  196. "Not an outbound session. Stopping",
  197. );
  198. return Ok(())
  199. }
  200. let mut external_addrs = self.settings.read().await.external_addrs.clone();
  201. // Auto-advertise the node's inbound address using the address that
  202. // was sent to use by the node in the version exchange.
  203. for external_addr in &mut external_addrs {
  204. let _ = Self::patch_inbound(&self.channel, external_addr);
  205. }
  206. if external_addrs.is_empty() {
  207. debug!(
  208. target: "net::protocol_address::send_my_addrs",
  209. "External addr not configured. Stopping",
  210. );
  211. return Ok(())
  212. }
  213. let mut addrs = vec![];
  214. for addr in external_addrs {
  215. let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
  216. addrs.push((addr, last_seen));
  217. }
  218. debug!(
  219. target: "net::protocol_address::send_my_addrs",
  220. "Broadcasting {} addresses", addrs.len(),
  221. );
  222. let ext_addr_msg = AddrsMessage { addrs };
  223. self.channel.send(&ext_addr_msg).await?;
  224. debug!(
  225. target: "net::protocol_address::send_my_addrs",
  226. "[END] channel address={}", self.channel.address(),
  227. );
  228. Ok(())
  229. }
  230. /// If the inbound is an Ipv6 address, then replace it with the ip address reported to
  231. /// us by the version exchange.
  232. ///
  233. /// Also used by ProtocolSeed.
  234. pub(super) fn patch_inbound(channel: &Channel, inbound: &mut Url) -> Option<()> {
  235. if inbound.scheme() != "tcp" && inbound.scheme() != "tcp+tls" {
  236. return None
  237. }
  238. let inbound_host = inbound.host()?;
  239. // Is it an Ipv6 listener?
  240. match inbound_host {
  241. Host::Ipv6(addr) => {
  242. // We are only interested if it's localhost
  243. if !addr.is_loopback() {
  244. return None
  245. }
  246. }
  247. _ => return None,
  248. }
  249. // We should loop over the endpoints from the listeners
  250. // But inbound session should be changed so the acceptors and listeners
  251. // are accessible.
  252. /*
  253. let Some(mut port) = inbound.port() else { continue };
  254. if port == 0 {
  255. }
  256. */
  257. // Get our auto-discovered IP
  258. let version = channel.get_version();
  259. let discover_host = version.connect_recv_addr.host()?;
  260. // Check the reported address is Ipv6
  261. let _ = match discover_host {
  262. Host::Ipv6(_) => {}
  263. _ => return None,
  264. };
  265. inbound.set_host(version.connect_recv_addr.host_str()).ok()?;
  266. Some(())
  267. }
  268. }
  269. #[async_trait]
  270. impl ProtocolBase for ProtocolAddress {
  271. /// Start the address protocol. If it's an outbound session and has an
  272. /// external address, send our external address. Run receive address
  273. /// and get address protocols on the protocol task manager. Then send
  274. /// get-address msg.
  275. async fn start(self: Arc<Self>, ex: Arc<Executor<'_>>) -> Result<()> {
  276. debug!(
  277. target: "net::protocol_address::start()",
  278. "START => address={}", self.channel.address(),
  279. );
  280. let settings = self.settings.read().await;
  281. let outbound_connections = settings.outbound_connections;
  282. let allowed_transports = settings.allowed_transports.clone();
  283. drop(settings);
  284. self.jobsman.clone().start(ex.clone());
  285. self.jobsman.clone().spawn(self.clone().send_my_addrs(), ex.clone()).await;
  286. self.jobsman.clone().spawn(self.clone().handle_receive_addrs(), ex.clone()).await;
  287. self.jobsman.spawn(self.clone().handle_receive_get_addrs(), ex).await;
  288. // Send get_address message.
  289. let get_addrs =
  290. GetAddrsMessage { max: outbound_connections as u32, transports: allowed_transports };
  291. self.channel.send(&get_addrs).await?;
  292. debug!(
  293. target: "net::protocol_address::start()",
  294. "END => address={}", self.channel.address(),
  295. );
  296. Ok(())
  297. }
  298. fn name(&self) -> &'static str {
  299. PROTO_NAME
  300. }
  301. }