diff options
Diffstat (limited to 'src/transport/libp2p/config.rs')
| -rw-r--r-- | src/transport/libp2p/config.rs | 117 |
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())) + } +} |
