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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
//! 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>,
/// Address ranges that matter most, best first (`Book::preference`).
pub(crate) prefer: 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 option `option`.
pub(super) fn parse_ranges(option: &str, ranges: &[String]) -> Result<Vec<IpRange>> {
ranges
.iter()
.map(|range| range.parse().with_context(|| option.to_owned()))
.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)?;
let ignore = parse_ranges("libp2p-ignore", &settings.libp2p_ignore)?;
let prefer = parse_ranges("libp2p-prefer", &settings.libp2p_prefer)?;
check_preferred(
&ignore,
&prefer,
&settings.libp2p_ignore,
&settings.libp2p_prefer,
)?;
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(())
}
/// A range both ignored and preferred: refused where all of the preferred one is
/// ignored (it would name nothing usable), a warning where only part of it is (the
/// ignored part stays left out). `ignore_given` and `prefer_given`: as written, for
/// the messages. Ranges nest or are apart, so there's nothing in between.
pub(super) fn check_preferred(
ignore: &[IpRange],
prefer: &[IpRange],
ignore_given: &[String],
prefer_given: &[String],
) -> Result<()> {
for (preferred, preferred_given) in prefer.iter().zip(prefer_given) {
for (ignored, ignored_given) in ignore.iter().zip(ignore_given) {
if ignored.covers(preferred) {
bail!(
"libp2p-prefer {preferred_given:?} is all in libp2p-ignore {ignored_given:?}: nothing there is used"
);
}
if preferred.covers(ignored) {
warn!(
"libp2p-prefer {preferred_given:?} has libp2p-ignore {ignored_given:?} in it: addresses there stay left out"
);
}
}
}
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("libp2p-ignore", &settings.libp2p_ignore)?,
prefer: parse_ranges("libp2p-prefer", &settings.libp2p_prefer)?,
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()))
}
}
|