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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
//! 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>,
/// Hosts on the internet (names or addresses) whose routes tell whether there is
/// one to the internet at all (`Routes::internet`).
pub(crate) internet_hosts: Vec<String>,
/// 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 node's keepalive interval (`--keepalive`): connections idle for a few of
/// them are closed (`idle_timeout`).
pub(crate) keepalive: Duration,
}
/// 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.libp2p_key_create && settings.libp2p_key_file.is_none() {
bail!("libp2p-key-create creates the key at libp2p-key-file; set that too");
}
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(),
settings.libp2p_key_create,
)?,
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)?,
internet_hosts: settings.libp2p_internet_hosts.clone(),
public: settings.libp2p_public,
memory: false,
keepalive: settings.keepalive,
})
}
/// The key in `path` (32 raw bytes, an Ed25519 secret key), created there with
/// `create` if there is no file; or a new one each start without a path: 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>, create: bool) -> Result<Keypair> {
let Some(path) = path else {
return Ok(Keypair::generate_ed25519());
};
let (mut bytes, created) = crate::files::key_file(
path,
"libp2p key",
create,
"libp2p-key-create",
"a new peer ID",
32,
)?;
if created {
info!(path = %path.display(), "Created a new 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()))
}
}
|