aboutsummaryrefslogtreecommitdiffstats
path: root/src/transport
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-30 16:32:23 +0100
committertv <tv@krebsco.de>2026-10-30 16:32:23 +0100
commitf091fb2a9188f686e5b1f9012c510a1b3c8ad840 (patch)
tree8821dfe3c63535762a798b85dfe8c0d850a9df90 /src/transport
parent0ee0cd19b7ceabf5d75e1b8fdd074a6e758bc6db (diff)
move transport config checks to respective modules
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/libp2p.rs59
-rw-r--r--src/transport/mod.rs21
-rw-r--r--src/transport/mycelium/mod.rs20
-rw-r--r--src/transport/tor.rs11
4 files changed, 96 insertions, 15 deletions
diff --git a/src/transport/libp2p.rs b/src/transport/libp2p.rs
index 2d67d2c..d023079 100644
--- a/src/transport/libp2p.rs
+++ b/src/transport/libp2p.rs
@@ -204,6 +204,48 @@ pub(crate) struct Libp2pConfig {
pub(crate) memory: bool,
}
+/// The multiaddrs of option `option`.
+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`.
+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`).
@@ -211,16 +253,7 @@ impl Libp2pConfig {
settings: &crate::config::Settings,
relay_only: bool,
) -> Result<Self> {
- let parse = |option: &str, addresses: &[String]| {
- addresses
- .iter()
- .map(|address| {
- address
- .parse::<Multiaddr>()
- .with_context(|| format!("{option} {address:?}"))
- })
- .collect::<Result<Vec<_>>>()
- };
+ let parse = parse_addresses;
Ok(Self {
key: Self::load_key(settings.libp2p_key_file.as_deref())?,
listen: parse("libp2p-listen", &settings.libp2p_listen)?,
@@ -230,11 +263,7 @@ impl Libp2pConfig {
continuum: !relay_only,
mdns: settings.libp2p_mdns,
upnp: settings.libp2p_upnp,
- ignore: settings
- .libp2p_ignore
- .iter()
- .map(|range| range.parse().context("libp2p-ignore"))
- .collect::<Result<Vec<_>>>()?,
+ ignore: parse_ranges(&settings.libp2p_ignore)?,
public: settings.libp2p_public,
memory: false,
})
diff --git a/src/transport/mod.rs b/src/transport/mod.rs
index d8c6e2b..fd3651b 100644
--- a/src/transport/mod.rs
+++ b/src/transport/mod.rs
@@ -34,6 +34,27 @@ compile_error!(
"continuum needs a transport: build with at least one of the mycelium, libp2p and tor features, e.g. `cargo build --features mycelium`"
);
+/// The options of the transports this build has, each checked by its transport when the
+/// configuration is loaded (`config::Settings::check`, after the names in `transports`):
+/// Mycelium's always (its conflicts are errors wherever they come from, as before);
+/// libp2p's and Tor's if the node uses them. Options of transports not built aren't
+/// checked: they're ignored, and said so (`config::Loaded::unused_transport_options`).
+pub(crate) fn check(settings: &crate::config::Settings) -> Result<()> {
+ let uses = |name: &str| settings.transports.iter().any(|used| used == name);
+ let _ = uses;
+ #[cfg(feature = "mycelium")]
+ mycelium::check(settings)?;
+ #[cfg(feature = "libp2p")]
+ if uses("libp2p") {
+ libp2p::check(settings)?;
+ }
+ #[cfg(feature = "tor")]
+ if uses("tor") {
+ tor::TorTransport::check(settings)?;
+ }
+ Ok(())
+}
+
/// Starts the transport `name` (one of `config::TRANSPORTS`) as `settings` configure
/// it: its scheme and the transport, or None if `stop` came first (some take a while to
/// start: a supervised Mycelium daemon, arti). `key`: the node key, which some prove
diff --git a/src/transport/mycelium/mod.rs b/src/transport/mycelium/mod.rs
index 7abcced..20abee8 100644
--- a/src/transport/mycelium/mod.rs
+++ b/src/transport/mycelium/mod.rs
@@ -91,6 +91,26 @@ pub(crate) struct MyceliumTransport {
local_id: String,
}
+/// This transport's options, checked when the configuration is loaded
+/// (`config::Settings::check`): a daemon elsewhere (`mycelium-rest-url`) by a URL, and
+/// none of the options only a supervised one takes with it; a private network with
+/// both its key and its name.
+pub(crate) fn check(settings: &crate::config::Settings) -> Result<()> {
+ if let Some(url) = &settings.mycelium_rest_url {
+ Url::parse(url).with_context(|| format!("mycelium-rest-url {url:?}"))?;
+ if let Some((name, _)) = settings.supervised_only().iter().find(|(_, set)| *set) {
+ anyhow::bail!(
+ "{name} is for a supervised Mycelium daemon and can't be combined with mycelium-rest-url"
+ );
+ }
+ }
+ // A private network has both; one alone would be ignored or invented.
+ if settings.mycelium_network_key_file.is_some() != settings.mycelium_network_name.is_some() {
+ anyhow::bail!("mycelium-network-key-file and mycelium-network-name go together");
+ }
+ Ok(())
+}
+
/// The transport as `settings` configure it (`transport::start`): its daemon supervised
/// (started, which can take a while) or one running elsewhere. None if `stop` came
/// first.
diff --git a/src/transport/tor.rs b/src/transport/tor.rs
index 8eb1d02..f2e0199 100644
--- a/src/transport/tor.rs
+++ b/src/transport/tor.rs
@@ -198,6 +198,17 @@ impl TorTransport {
/// while: it fetches what it needs to know of the Tor network). Until it is done,
/// dials wait for it (arti bootstraps on demand), and the onion service is published
/// once it is: the node starts without waiting for Tor.
+ /// This transport's options, checked when the configuration is loaded
+ /// (`config::Settings::check`), if the node uses it: where arti keeps its state.
+ pub(crate) fn check(settings: &crate::config::Settings) -> Result<()> {
+ if settings.tor_state_dir.is_none() {
+ bail!(
+ "tor needs tor-state-dir: where arti keeps its state, the onion service's key among it"
+ );
+ }
+ Ok(())
+ }
+
/// The transport as `settings` configure it (`transport::start`), proving `key`.
/// None if `stop` came first (bootstrapping arti can take a while).
pub(crate) async fn from_settings(