/ src / net / settings.rs
settings.rs
  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  
 19  use structopt::StructOpt;
 20  use url::Url;
 21  
 22  type BlacklistEntry = (String, Vec<String>, Vec<u16>);
 23  
 24  /// Ban policies definitions.
 25  ///
 26  /// If the ban policy is set to `Relaxed` will not ban peers in case
 27  /// they send a message without a corresponding MessageDispatcher.
 28  /// This is useful for nodes that may not be subscribed to protocols,
 29  /// such as Lilith. For most uses this should be set to `Strict`.
 30  ///
 31  /// TODO: this will be deprecated when we introduce the p2p resource
 32  /// mananger.
 33  #[derive(Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)]
 34  #[serde(rename_all = "lowercase")]
 35  pub enum BanPolicy {
 36      #[default]
 37      Strict,
 38  
 39      Relaxed,
 40  }
 41  
 42  /// P2P network settings. The scope of this is a P2P network instance
 43  /// configured by the library user.
 44  #[derive(Debug, Clone)]
 45  pub struct Settings {
 46      /// Only used for debugging, compromises privacy when set
 47      pub node_id: String,
 48      /// P2P accept addresses the instance listens on for inbound connections
 49      pub inbound_addrs: Vec<Url>,
 50      /// P2P external addresses the instance advertises so other peers can
 51      /// reach us and connect to us, as long as inbound addrs are configured
 52      pub external_addrs: Vec<Url>,
 53      /// Peer nodes to manually connect to
 54      pub peers: Vec<Url>,
 55      /// Seed nodes to connect to for peer discovery and/or advertising our
 56      /// own external addresses
 57      pub seeds: Vec<Url>,
 58      /// Magic bytes should be unique per P2P network.
 59      /// Avoid bleeding of networks.
 60      pub magic_bytes: MagicBytes,
 61      /// Application version, used for convenient protocol matching
 62      pub app_version: semver::Version,
 63      /// Whitelisted network transports for outbound connections
 64      pub allowed_transports: Vec<String>,
 65      /// Transports allowed to be mixed (tcp, tcp+tls, tor, tor+tls)
 66      /// When transport is added to this list the corresponding transport
 67      /// in allowed_transports is used to connect to the node.
 68      /// Supported mixing scenarios include
 69      /// allowed_transport | mixed_transport
 70      ///        tor        |     tcp
 71      ///       tor+tls     |    tcp+tls
 72      ///       socks5      |      tor
 73      ///       socks5      |      tcp
 74      ///      socks5+tls   |    tor+tls
 75      ///      socks5+tls   |    tcp+tls
 76      pub mixed_transports: Vec<String>,
 77      /// Tor socks5 proxy to connect to when socks5 or socks5+tls are added to allowed transports
 78      /// and transport mixing is enabled
 79      pub tor_socks5_proxy: Option<Url>,
 80      /// Nym socks5 proxy to connect to when socks5 or socks5+tls are added to allowed transports
 81      /// and transport mixing is enabled
 82      pub nym_socks5_proxy: Option<Url>,
 83      /// I2p Socks5 proxy to connect to i2p eepsite (hidden services)
 84      pub i2p_socks5_proxy: Url,
 85      /// Outbound connection slots number, this many connections will be
 86      /// attempted. (This does not include manual connections)
 87      pub outbound_connections: usize,
 88      /// Inbound connection slots number, this many active listening connections
 89      /// will be allowed. (This does not include manual connections)
 90      pub inbound_connections: usize,
 91      /// Outbound connection timeout (in seconds)
 92      pub outbound_connect_timeout: u64,
 93      /// Exchange versions (handshake) timeout (in seconds)
 94      pub channel_handshake_timeout: u64,
 95      /// Ping-pong exchange execution interval (in seconds)
 96      pub channel_heartbeat_interval: u64,
 97      /// Allow localnet hosts
 98      pub localnet: bool,
 99      /// Cooling off time for peer discovery when unsuccessful
100      pub outbound_peer_discovery_cooloff_time: u64,
101      /// Time between peer discovery attempts
102      pub outbound_peer_discovery_attempt_time: u64,
103      /// Maximum number of addresses (with preferred transports) to receive from
104      /// seeds and peers.
105      /// If undefined, `outbound_connections` will be used instead.
106      pub getaddrs_max: Option<u32>,
107      /// P2P datastore path
108      pub p2p_datastore: Option<String>,
109      /// Hostlist storage path
110      pub hostlist: Option<String>,
111      /// Pause interval within greylist refinery process
112      pub greylist_refinery_interval: u64,
113      /// Percent of connections to come from the whitelist
114      pub white_connect_percent: usize,
115      /// Number of goldlist connections
116      pub gold_connect_count: usize,
117      /// If this is true, strictly follow the gold_connect_count and
118      /// white_connect_percent settings. Otherwise, connect to greylist
119      /// entries if we have no white or gold connections.
120      pub slot_preference_strict: bool,
121      /// Number of seconds with no connections after which refinery
122      /// process is paused.
123      pub time_with_no_connections: u64,
124      /// Nodes to avoid interacting with for the duration of the program,
125      /// in the format ["host", ["scheme", "scheme"], [port, port]]
126      /// If scheme is left empty it will default to "tcp+tls".
127      /// If ports are left empty all ports from this peer will be blocked.
128      pub blacklist: Vec<BlacklistEntry>,
129      /// Do not ban nodes that send messages without dispatchers if set
130      /// to `Relaxed`. For most uses, should be set to `Strict`.
131      pub ban_policy: BanPolicy,
132  }
133  
134  impl Default for Settings {
135      fn default() -> Self {
136          let version = option_env!("CARGO_PKG_VERSION").unwrap_or("0.0.0");
137          let app_version = semver::Version::parse(version).unwrap();
138  
139          Self {
140              node_id: String::new(),
141              inbound_addrs: vec![],
142              external_addrs: vec![],
143              magic_bytes: Default::default(),
144              peers: vec![],
145              seeds: vec![],
146              app_version,
147              allowed_transports: vec!["tcp+tls".to_string()],
148              mixed_transports: vec![],
149              tor_socks5_proxy: None,
150              nym_socks5_proxy: None,
151              i2p_socks5_proxy: Url::parse("socks5://127.0.0.1:4447").unwrap(),
152              outbound_connections: 8,
153              inbound_connections: 8,
154              outbound_connect_timeout: 15,
155              channel_handshake_timeout: 10,
156              channel_heartbeat_interval: 30,
157              localnet: false,
158              outbound_peer_discovery_cooloff_time: 30,
159              outbound_peer_discovery_attempt_time: 5,
160              getaddrs_max: None,
161              p2p_datastore: None,
162              hostlist: None,
163              greylist_refinery_interval: 15,
164              white_connect_percent: 70,
165              gold_connect_count: 2,
166              slot_preference_strict: false,
167              time_with_no_connections: 30,
168              blacklist: vec![],
169              ban_policy: BanPolicy::Strict,
170          }
171      }
172  }
173  
174  // The following is used so we can have P2P settings configurable
175  // from TOML files.
176  
177  /// Distinguishes distinct P2P networks
178  #[derive(serde::Deserialize, Debug, Clone)]
179  pub struct MagicBytes(pub [u8; 4]);
180  
181  impl Default for MagicBytes {
182      fn default() -> Self {
183          Self([0xd9, 0xef, 0xb6, 0x7d])
184      }
185  }
186  
187  /// Defines the network settings.
188  #[derive(Clone, Debug, serde::Deserialize, structopt::StructOpt, structopt_toml::StructOptToml)]
189  #[structopt()]
190  pub struct SettingsOpt {
191      /// P2P accept address node listens to for inbound connections
192      #[serde(default)]
193      #[structopt(long = "accept")]
194      pub inbound: Vec<Url>,
195  
196      /// Outbound connection slots number
197      #[structopt(long = "outbound-slots")]
198      pub outbound_connections: Option<usize>,
199  
200      /// Inbound connection slots number
201      #[structopt(long = "inbound-slots")]
202      pub inbound_connections: Option<usize>,
203  
204      #[serde(default)]
205      #[structopt(skip)]
206      /// Magic bytes used to distinguish P2P distinct networks and
207      /// avoid nodes bleeding due to user config error.
208      pub magic_bytes: MagicBytes,
209  
210      /// P2P external addresses node advertises so other peers can
211      /// reach us and connect to us, as long as inbound addresses
212      /// are also configured
213      #[serde(default)]
214      #[structopt(long)]
215      pub external_addrs: Vec<Url>,
216  
217      /// Peer nodes to manually connect to
218      #[serde(default)]
219      #[structopt(long)]
220      pub peers: Vec<Url>,
221  
222      /// Seed nodes to connect to for peers retrieval and/or
223      /// advertising our own external addresses
224      #[serde(default)]
225      #[structopt(long)]
226      pub seeds: Vec<Url>,
227  
228      /// Connection establishment timeout in seconds
229      #[structopt(skip)]
230      pub outbound_connect_timeout: Option<u64>,
231  
232      /// Exchange versions (handshake) timeout in seconds
233      #[structopt(skip)]
234      pub channel_handshake_timeout: Option<u64>,
235  
236      /// Ping-pong exchange execution interval in seconds
237      #[structopt(skip)]
238      pub channel_heartbeat_interval: Option<u64>,
239  
240      /// Only used for debugging. Compromises privacy when set.
241      #[serde(default)]
242      #[structopt(skip)]
243      pub node_id: String,
244  
245      /// Preferred transports for outbound connections
246      #[serde(default)]
247      #[structopt(long = "transports")]
248      pub allowed_transports: Option<Vec<String>>,
249  
250      /// Transports allowed to be mixed (tcp, tcp+tls, tor, tor+tls)
251      /// When transport is added to this list the corresponding transport
252      /// in allowed_transports is used to connect to the node.
253      /// Supported mixing scenarios include
254      /// allowed_transport | mixed_transport
255      ///        tor        |     tcp
256      ///       tor+tls     |    tcp+tls
257      ///       socks5      |      tor
258      ///       socks5      |      tcp
259      ///      socks5+tls   |    tor+tls
260      ///      socks5+tls   |    tcp+tls
261      #[serde(default)]
262      #[structopt(long = "mixed-transports")]
263      pub mixed_transports: Option<Vec<String>>,
264  
265      /// Tor socks5 proxy to connect to when socks5 or socks5+tls are added to allowed transports
266      /// and transport mixing is enabled
267      #[structopt(long)]
268      pub tor_socks5_proxy: Option<Url>,
269  
270      /// Nym socks5 proxy to connect to when socks5 or socks5+tls are added to allowed transports
271      /// and transport mixing is enabled
272      #[structopt(long)]
273      pub nym_socks5_proxy: Option<Url>,
274  
275      /// I2p Socks5 proxy to connect to i2p eepsite (hidden services)
276      #[structopt(long)]
277      pub i2p_socks5_proxy: Option<Url>,
278  
279      /// If this is true, strictly follow the gold_connect_count and
280      /// white_connect_percent settings. Otherwise, connect to greylist
281      /// entries if we have no white or gold connections.
282      #[serde(default)]
283      #[structopt(long)]
284      pub localnet: bool,
285  
286      /// Cooling off time for peer discovery when unsuccessful
287      #[structopt(skip)]
288      pub outbound_peer_discovery_cooloff_time: Option<u64>,
289  
290      /// Time between peer discovery attempts
291      #[structopt(skip)]
292      pub outbound_peer_discovery_attempt_time: Option<u64>,
293  
294      /// Maximum number of addresses (with preferred transports) to receive from
295      /// seeds and peers.
296      /// If undefined, `outbound_connections` will be used instead.
297      #[structopt(skip)]
298      pub getaddrs_max: Option<u32>,
299  
300      /// P2P datastore path
301      #[serde(default)]
302      #[structopt(long)]
303      pub p2p_datastore: Option<String>,
304  
305      /// Hosts .tsv file to use
306      #[serde(default)]
307      #[structopt(long)]
308      pub hostlist: Option<String>,
309  
310      /// Pause interval within greylist refinery process
311      #[structopt(skip)]
312      pub greylist_refinery_interval: Option<u64>,
313  
314      /// Number of whitelist connections
315      #[structopt(skip)]
316      pub white_connect_percent: Option<usize>,
317  
318      /// Number of goldlist connections
319      #[structopt(skip)]
320      pub gold_connect_count: Option<usize>,
321  
322      /// Allow localnet hosts
323      #[serde(default)]
324      #[structopt(long)]
325      pub slot_preference_strict: bool,
326  
327      /// Number of seconds with no connections after which refinery
328      /// process is paused.
329      #[structopt(skip)]
330      pub time_with_no_connections: Option<u64>,
331  
332      /// Nodes to avoid interacting with for the duration of the program,
333      /// in the format ["host", ["scheme", "scheme"], [port, port]]
334      /// If scheme is left empty it will default to "tcp+tls".
335      /// If ports are left empty all ports from this peer will be blocked.
336      #[serde(default)]
337      #[structopt(skip)]
338      pub blacklist: Vec<BlacklistEntry>,
339  
340      /// Do not ban nodes that send messages without dispatchers if set
341      /// to `Relaxed`. For most uses, should be set to `Strict`.
342      #[serde(default)]
343      #[structopt(skip)]
344      pub ban_policy: BanPolicy,
345  }
346  
347  impl From<SettingsOpt> for Settings {
348      fn from(opt: SettingsOpt) -> Self {
349          let def = Settings::default();
350  
351          Self {
352              node_id: opt.node_id,
353              inbound_addrs: opt.inbound,
354              external_addrs: opt.external_addrs,
355              magic_bytes: opt.magic_bytes,
356              peers: opt.peers,
357              seeds: opt.seeds,
358              app_version: def.app_version,
359              allowed_transports: opt.allowed_transports.unwrap_or(def.allowed_transports),
360              mixed_transports: opt.mixed_transports.unwrap_or(def.mixed_transports),
361              tor_socks5_proxy: opt.tor_socks5_proxy,
362              nym_socks5_proxy: opt.nym_socks5_proxy,
363              i2p_socks5_proxy: opt.i2p_socks5_proxy.unwrap_or(def.i2p_socks5_proxy),
364              outbound_connections: opt.outbound_connections.unwrap_or(def.outbound_connections),
365              inbound_connections: opt.inbound_connections.unwrap_or(def.inbound_connections),
366              outbound_connect_timeout: opt
367                  .outbound_connect_timeout
368                  .unwrap_or(def.outbound_connect_timeout),
369              channel_handshake_timeout: opt
370                  .channel_handshake_timeout
371                  .unwrap_or(def.channel_handshake_timeout),
372              channel_heartbeat_interval: opt
373                  .channel_heartbeat_interval
374                  .unwrap_or(def.channel_heartbeat_interval),
375              localnet: opt.localnet,
376              outbound_peer_discovery_cooloff_time: opt
377                  .outbound_peer_discovery_cooloff_time
378                  .unwrap_or(def.outbound_peer_discovery_cooloff_time),
379              outbound_peer_discovery_attempt_time: opt
380                  .outbound_peer_discovery_attempt_time
381                  .unwrap_or(def.outbound_peer_discovery_attempt_time),
382              getaddrs_max: opt.getaddrs_max,
383              p2p_datastore: opt.p2p_datastore,
384              hostlist: opt.hostlist,
385              greylist_refinery_interval: opt
386                  .greylist_refinery_interval
387                  .unwrap_or(def.greylist_refinery_interval),
388              white_connect_percent: opt.white_connect_percent.unwrap_or(def.white_connect_percent),
389              gold_connect_count: opt.gold_connect_count.unwrap_or(def.gold_connect_count),
390              slot_preference_strict: opt.slot_preference_strict,
391              time_with_no_connections: opt
392                  .time_with_no_connections
393                  .unwrap_or(def.time_with_no_connections),
394              blacklist: opt.blacklist,
395              ban_policy: opt.ban_policy,
396          }
397      }
398  }