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
|
//! Admission with a swarm key: only peers that proved it get past `admit`.
use tracing::{debug, info, trace, warn};
use super::handshake::remember_peer;
use crate::state::{AppState, HelloState, Standing};
use crate::transport::ParsedMessage;
/// With a swarm key, only peers that proved it get past this point. A HELLO or
/// HELLO_REPLY must carry a valid tag, and it admits its sender; anything else is only
/// accepted from a peer admitted that way. Everything else is ignored without a reply,
/// so strangers learn nothing, not even whether we know the key.
pub(super) async fn admit(state: &AppState, peer: &str, message: &ParsedMessage) -> bool {
let Some(key) = &state.swarm_key else {
return true;
};
let local = state.local_id();
let proof = match message {
ParsedMessage::Hello(hello) => Some(key.verify_hello(
&hello.auth,
hello.swarm_id.as_deref().unwrap_or(""),
peer,
local,
)),
ParsedMessage::HelloReply(reply) => {
Some(key.verify_hello_reply(&reply.auth, &reply.swarm_id, peer, local))
}
_ => None,
};
match proof {
Some(true) => {
remember_peer(state, peer).await;
if let Some(peer_state) = state.get_peer_state(peer).await {
let mut peer_state = peer_state.lock().await;
if peer_state.standing == Standing::Stranger {
peer_state.standing = Standing::Admitted;
debug!(peer = %peer, "Peer proved the swarm key");
}
}
true
}
Some(false) => {
// A known peer with a wrong key (e.g. one that was given another key) loses
// its admission until it proves the right one, and with it its membership:
// we stop syncing our document to it, not just listening to it.
if let Some(peer_state) = state.get_peer_state(peer).await {
let mut peer_state = peer_state.lock().await;
if peer_state.standing.is_admitted() {
warn!(peer = %peer, "Peer no longer proves the swarm key; dropping its membership");
}
peer_state.standing = Standing::Stranger;
peer_state.hello_state = HelloState::NotSent;
peer_state.reset_sync();
}
// The one place an operator can see why a node can't join: rate limited,
// since anyone can send us handshakes.
if let Some(suppressed) = key.note_rejection() {
info!(
peer = %peer,
suppressed,
"Rejected handshake without a valid swarm key proof"
);
}
false
}
None => {
let admitted = match state.get_peer_state(peer).await {
Some(peer_state) => peer_state.lock().await.standing.is_admitted(),
None => false,
};
if !admitted {
trace!(peer = %peer, "Ignoring message from a peer that hasn't proven the swarm key");
}
admitted
}
}
}
|