aboutsummaryrefslogtreecommitdiffstats
path: root/src/transport/libp2p/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/libp2p/config.rs')
-rw-r--r--src/transport/libp2p/config.rs117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/transport/libp2p/config.rs b/src/transport/libp2p/config.rs
new file mode 100644
index 0000000..012999d
--- /dev/null
+++ b/src/transport/libp2p/config.rs
@@ -0,0 +1,117 @@
+//! What the options make of the libp2p transport (`Libp2pConfig`), and their checks.
+
+use super::*;
+
+/// What a libp2p transport is made with.
+pub(crate) struct Libp2pConfig {
+ pub(crate) key: Keypair,
+ /// Multiaddrs to listen on.
+ pub(crate) listen: Vec<Multiaddr>,
+ /// Multiaddrs to publish instead of the listen addresses, if any.
+ pub(crate) announce: Vec<Multiaddr>,
+ /// Relays to reserve a slot on (multiaddrs; without the relay's peer ID, a connection
+ /// finds it out).
+ pub(crate) relays: Vec<Multiaddr>,
+ /// Relay for other nodes.
+ pub(crate) relay: bool,
+ /// Speak continuum (`PROTOCOL`): not on a node that only relays (`--relay-only`),
+ /// which nobody should take for a node.
+ pub(crate) continuum: bool,
+ /// Find peers on the LAN (mDNS).
+ pub(crate) mdns: bool,
+ /// Ask the router to forward our listen ports (UPnP), and publish where.
+ pub(crate) upnp: bool,
+ /// Address ranges neither published nor dialled, nor connected over (`Ignoring`).
+ pub(crate) ignore: Vec<IpRange>,
+ /// Use public infrastructure: the IPFS DHT, public relays.
+ pub(crate) public: bool,
+ /// libp2p's in-memory transport instead of TCP and QUIC: for tests.
+ pub(crate) memory: bool,
+}
+
+/// The multiaddrs of option `option`.
+pub(super) fn parse_addresses(option: &str, addresses: &[String]) -> Result<Vec<Multiaddr>> {
+ addresses
+ .iter()
+ .map(|address| {
+ address
+ .parse::<Multiaddr>()
+ .with_context(|| format!("{option} {address:?}"))
+ })
+ .collect()
+}
+
+/// The ranges of `libp2p-ignore`.
+pub(super) fn parse_ranges(ranges: &[String]) -> Result<Vec<IpRange>> {
+ ranges
+ .iter()
+ .map(|range| range.parse().context("libp2p-ignore"))
+ .collect()
+}
+
+/// This transport's options, checked when the configuration is loaded
+/// (`config::Settings::check`), so `--print-config` tells a wrong one too: the
+/// multiaddrs and ranges parse, and a relay that is no node (`--relay-only`) can be
+/// dialled and keeps its peer ID.
+pub(crate) fn check(settings: &crate::config::Settings) -> Result<()> {
+ parse_addresses("libp2p-listen", &settings.libp2p_listen)?;
+ parse_addresses("libp2p-announce", &settings.libp2p_announce)?;
+ parse_addresses("libp2p-relays", &settings.libp2p_relays)?;
+ parse_ranges(&settings.libp2p_ignore)?;
+ if settings.relay_only {
+ if settings.libp2p_listen.is_empty() {
+ bail!("relay-only needs libp2p-listen: where nodes reach the relay");
+ }
+ if settings.libp2p_key_file.is_none() {
+ bail!(
+ "relay-only needs libp2p-key-file: without it, the relay's peer ID changes with every start and nodes lose it"
+ );
+ }
+ }
+ Ok(())
+}
+
+impl Libp2pConfig {
+ /// The configuration `settings` give; `relay_only`: a relay that is no node
+ /// (`--relay-only`).
+ pub(crate) fn from_settings(
+ settings: &crate::config::Settings,
+ relay_only: bool,
+ ) -> Result<Self> {
+ let parse = parse_addresses;
+ Ok(Self {
+ key: Self::load_key(settings.libp2p_key_file.as_deref())?,
+ listen: parse("libp2p-listen", &settings.libp2p_listen)?,
+ announce: parse("libp2p-announce", &settings.libp2p_announce)?,
+ relays: parse("libp2p-relays", &settings.libp2p_relays)?,
+ relay: settings.libp2p_relay || relay_only,
+ continuum: !relay_only,
+ mdns: settings.libp2p_mdns,
+ upnp: settings.libp2p_upnp,
+ ignore: parse_ranges(&settings.libp2p_ignore)?,
+ public: settings.libp2p_public,
+ memory: false,
+ })
+ }
+
+ /// The key in `path` (32 raw bytes, an Ed25519 secret key), or a new one each start
+ /// without a file: the peer ID only says where a node is, so a new one costs nothing
+ /// but the WHO that finds it again (`transport::identity`).
+ pub(crate) fn load_key(path: Option<&Path>) -> Result<Keypair> {
+ let Some(path) = path else {
+ return Ok(Keypair::generate_ed25519());
+ };
+ let mut bytes = std::fs::read(path)
+ .with_context(|| format!("Reading the libp2p key from {}", path.display()))?;
+ crate::swarm::auth::warn_if_readable_by_others(path, "libp2p key");
+ if bytes.len() != 32 {
+ bail!(
+ "The libp2p key in {} has {} bytes; it has 32",
+ path.display(),
+ bytes.len()
+ );
+ }
+ Keypair::ed25519_from_bytes(&mut bytes)
+ .map_err(|error| anyhow!("The libp2p key in {}: {error}", path.display()))
+ }
+}