1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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::files::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()))
}
}
|