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
use std::net::SocketAddrV4;
use tracing::info;
use crate::RequestSpecific;
use crate::common::messages::MessageType;
use crate::core::Core;
use crate::core::supports_signed_peers;
use crate::common::{Id, Node, RequestTypeSpecific};
impl Core {
pub fn handle_request(
&mut self,
from: SocketAddrV4,
request_from_read_only_node: bool,
version: Option<[u8; 4]>,
request_specific: RequestSpecific,
) -> (Option<MessageType>, bool) {
self.maybe_add_node_from_request(
from,
version,
request_from_read_only_node,
&request_specific,
);
let should_repopulate_routing_tables =
self.does_verify_our_new_public_address_with_self_ping(from, &request_specific);
let response = if self.server_mode {
let server = &mut self.server;
let response = server.handle_request(
&self.routing_table,
&self.signed_peers_routing_table,
from,
request_specific,
);
match response {
Some(MessageType::Error(_)) | Some(MessageType::Response(_)) => response,
_ => None,
}
} else {
None
};
(response, should_repopulate_routing_tables)
}
/// In client mode, we never add to our table any node contacting us
/// without querying it first, to avoid eclipse attacks.
///
/// While bootstrapping though, we can't be that picky, we have two
/// reasons to except that rule:
///
/// 1. first node creating the DHT;
/// without this exception, the bootstrapping node's routing table will never be populated.
/// 2. Bootstrapping signed_peers_routing_table requires that we latch to any node
/// that claims to support it.
/// In `periodic_node_maintaenance` fake unresponsive nodes will be removed.
/// And either way we prioritize secure nodes, so making up nodes from same
// machine won't have much effect.
fn maybe_add_node_from_request(
&mut self,
from: SocketAddrV4,
version: Option<[u8; 4]>,
request_from_read_only_node: bool,
request_specific: &RequestSpecific,
) {
if self.server_mode
&& !request_from_read_only_node
&& let RequestTypeSpecific::FindNode(ref param) = request_specific.request_type
{
let node = Node::new(param.target, from);
let supports_signed_peers = supports_signed_peers(version);
if self.bootstrap.is_empty() {
self.routing_table.add(node.clone());
if supports_signed_peers {
self.signed_peers_routing_table.add(node);
}
} else if supports_signed_peers {
self.signed_peers_routing_table.add(node);
}
}
}
/// Check an incoming request, and if it is a PING request, with our own
/// id and from our own address, then we assume that the ip address we are being
/// told is valid.
// TODO: can this be spoofed? should we check the `tid` as well to be sure?
fn does_verify_our_new_public_address_with_self_ping(
&mut self,
from: SocketAddrV4,
request_specific: &RequestSpecific,
) -> bool {
if let Some(our_address) = self.public_address {
let is_ping = matches!(request_specific.request_type, RequestTypeSpecific::Ping);
if from == our_address && is_ping {
self.firewalled = false;
let ipv4 = our_address.ip();
// Restarting our routing table with new secure Id if necessary.
if !self.id().is_valid_for_ip(*ipv4) {
let new_id = Id::from_ipv4(*ipv4);
info!(
"Our current id {} is not valid for adrsess {}. Using new id {}",
self.id(),
our_address,
new_id
);
self.routing_table.reset_id(new_id);
self.signed_peers_routing_table.reset_id(new_id);
return true;
}
}
}
false
}
}