signed node info

This commit is contained in:
John Smith
2022-05-10 21:49:42 -04:00
parent 3b2f4d184f
commit 912869d329
14 changed files with 635 additions and 283 deletions

View File

@@ -37,8 +37,8 @@ pub struct BucketEntry {
min_max_version: Option<(u8, u8)>,
seen_our_node_info: bool,
last_connection: Option<(ConnectionDescriptor, u64)>,
node_info: NodeInfo,
local_node_info: LocalNodeInfo,
opt_signed_node_info: Option<SignedNodeInfo>,
opt_local_node_info: Option<LocalNodeInfo>,
peer_stats: PeerStats,
latency_stats_accounting: LatencyStatsAccounting,
transfer_stats_accounting: TransferStatsAccounting,
@@ -52,8 +52,8 @@ impl BucketEntry {
min_max_version: None,
seen_our_node_info: false,
last_connection: None,
node_info: NodeInfo::default(),
local_node_info: LocalNodeInfo::default(),
opt_signed_node_info: None,
opt_local_node_info: None,
latency_stats_accounting: LatencyStatsAccounting::new(),
transfer_stats_accounting: TransferStatsAccounting::new(),
peer_stats: PeerStats {
@@ -107,26 +107,44 @@ impl BucketEntry {
move |e1, e2| Self::cmp_fastest_reliable(cur_ts, e1, e2)
}
pub fn update_node_info(&mut self, node_info: NodeInfo) {
self.node_info = node_info
pub fn update_node_info(&mut self, signed_node_info: SignedNodeInfo) {
self.opt_signed_node_info = Some(signed_node_info);
}
pub fn update_local_node_info(&mut self, local_node_info: LocalNodeInfo) {
self.local_node_info = local_node_info
self.opt_local_node_info = Some(local_node_info)
}
pub fn node_info(&self) -> &NodeInfo {
&self.node_info
pub fn has_node_info(&self) -> bool {
self.opt_signed_node_info.is_some()
}
pub fn local_node_info(&self) -> &LocalNodeInfo {
&self.local_node_info
}
pub fn peer_info(&self, key: DHTKey) -> PeerInfo {
PeerInfo {
node_id: NodeId::new(key),
node_info: self.node_info.clone(),
pub fn has_valid_signed_node_info(&self) -> bool {
if let Some(sni) = &self.opt_signed_node_info {
sni.signature.valid
} else {
false
}
}
pub fn has_local_node_info(&self) -> bool {
self.opt_local_node_info.is_some()
}
pub fn node_info(&self) -> Option<NodeInfo> {
self.opt_signed_node_info
.as_ref()
.map(|s| s.node_info.clone())
}
pub fn local_node_info(&self) -> Option<LocalNodeInfo> {
self.opt_local_node_info.clone()
}
pub fn peer_info(&self, key: DHTKey) -> Option<PeerInfo> {
self.opt_signed_node_info.as_ref().map(|s| PeerInfo {
node_id: NodeId::new(key),
signed_node_info: s.clone(),
})
}
pub fn set_last_connection(&mut self, last_connection: ConnectionDescriptor, timestamp: u64) {
self.last_connection = Some((last_connection, timestamp));
}

View File

@@ -22,17 +22,20 @@ impl RoutingTable {
let entry = params.1.as_ref().unwrap();
// skip nodes on our local network here
if entry.local_node_info().has_dial_info() {
if entry.local_node_info().is_some() {
return false;
}
// does it have matching public dial info?
entry
.node_info()
.first_filtered_dial_info_detail(|did| {
did.matches_filter(&dial_info_filter1)
.map(|n| {
n.first_filtered_dial_info_detail(|did| {
did.matches_filter(&dial_info_filter1)
})
.is_some()
})
.is_some()
.unwrap_or(false)
},
)),
// transform
@@ -49,16 +52,30 @@ impl RoutingTable {
// Get our own node's peer info (public node info) so we can share it with other nodes
pub fn get_own_peer_info(&self) -> PeerInfo {
PeerInfo::new(NodeId::new(self.node_id()), self.get_own_signed_node_info())
}
pub fn get_own_signed_node_info(&self) -> SignedNodeInfo {
let node_id = NodeId::new(self.node_id());
let secret = self.node_id_secret();
SignedNodeInfo::with_secret(self.get_own_node_info(), node_id, &secret).unwrap()
}
pub fn get_own_node_info(&self) -> NodeInfo {
let netman = self.network_manager();
let relay_node = netman.relay_node();
PeerInfo {
node_id: NodeId::new(self.node_id()),
node_info: NodeInfo {
network_class: netman.get_network_class().unwrap_or(NetworkClass::Invalid),
outbound_protocols: netman.get_protocol_config().unwrap_or_default().outbound,
dial_info_detail_list: self.dial_info_details(RoutingDomain::PublicInternet),
relay_peer_info: relay_node.map(|rn| Box::new(rn.peer_info())),
},
NodeInfo {
network_class: netman.get_network_class().unwrap_or(NetworkClass::Invalid),
outbound_protocols: netman.get_protocol_config().unwrap_or_default().outbound,
dial_info_detail_list: self.dial_info_details(RoutingDomain::PublicInternet),
relay_peer_info: relay_node.and_then(|rn| rn.peer_info().map(Box::new)),
}
}
pub fn filter_has_valid_signed_node_info(kv: &(&DHTKey, Option<&mut BucketEntry>)) -> bool {
match &kv.1 {
None => true,
Some(b) => b.has_node_info(),
}
}
@@ -68,7 +85,7 @@ impl RoutingTable {
) -> PeerInfo {
match &kv.1 {
None => own_peer_info.clone(),
Some(entry) => entry.peer_info(*kv.0),
Some(entry) => entry.peer_info(*kv.0).unwrap(),
}
}

View File

@@ -482,13 +482,13 @@ impl RoutingTable {
// Shortcut function to add a node to our routing table if it doesn't exist
// and add the dial info we have for it, since that's pretty common
pub fn register_node_with_node_info(
pub fn register_node_with_signed_node_info(
&self,
node_id: DHTKey,
node_info: NodeInfo,
signed_node_info: SignedNodeInfo,
) -> Result<NodeRef, String> {
let nr = self.create_node_ref(node_id, |e| {
e.update_node_info(node_info);
e.update_node_info(signed_node_info);
})?;
Ok(nr)
@@ -542,7 +542,11 @@ impl RoutingTable {
// Ensure it's not dead
if !matches!(entry.state(cur_ts), BucketEntryState::Dead) {
// Ensure this node is not on our local network
if !entry.local_node_info().has_dial_info() {
if !entry
.local_node_info()
.map(|l| l.has_dial_info())
.unwrap_or(false)
{
// Ensure we have the node's status
if let Some(node_status) = &entry.peer_stats().status {
// Ensure the node will relay
@@ -569,8 +573,36 @@ impl RoutingTable {
best_inbound_relay
}
pub async fn find_self(&self, node_ref: NodeRef) -> Result<Vec<NodeRef>, String> {
pub fn register_find_node_answer(&self, fna: FindNodeAnswer) -> Result<Vec<NodeRef>, String> {
let node_id = self.node_id();
// register nodes we'd found
let mut out = Vec::<NodeRef>::with_capacity(fna.peers.len());
for p in fna.peers {
// if our own node if is in the list then ignore it, as we don't add ourselves to our own routing table
if p.node_id.key == node_id {
continue;
}
// register the node if it's new
let nr = self
.register_node_with_signed_node_info(p.node_id.key, p.signed_node_info.clone())
.map_err(map_to_string)
.map_err(logthru_rtab!(
"couldn't register node {} at {:?}",
p.node_id.key,
&p.signed_node_info
))?;
out.push(nr);
}
Ok(out)
}
pub async fn find_node(
&self,
node_ref: NodeRef,
node_id: DHTKey,
) -> Result<Vec<NodeRef>, String> {
let rpc_processor = self.rpc_processor();
let res = rpc_processor
@@ -594,29 +626,14 @@ impl RoutingTable {
self.register_find_node_answer(res)
}
pub fn register_find_node_answer(&self, fna: FindNodeAnswer) -> Result<Vec<NodeRef>, String> {
pub async fn find_self(&self, node_ref: NodeRef) -> Result<Vec<NodeRef>, String> {
let node_id = self.node_id();
self.find_node(node_ref, node_id).await
}
// register nodes we'd found
let mut out = Vec::<NodeRef>::with_capacity(fna.peers.len());
for p in fna.peers {
// if our own node if is in the list then ignore it, as we don't add ourselves to our own routing table
if p.node_id.key == node_id {
continue;
}
// register the node if it's new
let nr = self
.register_node_with_node_info(p.node_id.key, p.node_info.clone())
.map_err(map_to_string)
.map_err(logthru_rtab!(
"couldn't register node {} at {:?}",
p.node_id.key,
&p.node_info
))?;
out.push(nr);
}
Ok(out)
pub async fn find_target(&self, node_ref: NodeRef) -> Result<Vec<NodeRef>, String> {
let node_id = node_ref.node_id();
self.find_node(node_ref, node_id).await
}
pub async fn reverse_find_node(&self, node_ref: NodeRef, wide: bool) {
@@ -681,18 +698,39 @@ impl RoutingTable {
let mut unord = FuturesUnordered::new();
for (k, v) in bsmap {
log_rtab!(" bootstrapping {} with {:?}", k.encode(), &v);
// Make invalid signed node info (no signature)
let nr = self
.register_node_with_node_info(
.register_node_with_signed_node_info(
k,
NodeInfo {
SignedNodeInfo::with_no_signature(NodeInfo {
network_class: NetworkClass::InboundCapable, // Bootstraps are always inbound capable
outbound_protocols: ProtocolSet::empty(), // Bootstraps do not participate in relaying and will not make outbound requests
dial_info_detail_list: v, // Dial info is as specified in the bootstrap list
relay_peer_info: None, // Bootstraps never require a relay themselves
},
}),
)
.map_err(logthru_rtab!("Couldn't add bootstrap node: {}", k))?;
unord.push(self.reverse_find_node(nr, true));
// Add this our futures to process in parallel
let this = self.clone();
unord.push(async move {
// Need VALID signed peer info, so ask bootstrap to find_node of itself
// which will ensure it has the bootstrap's signed peer info as part of the response
let _ = this.find_target(nr.clone()).await;
// Ensure we got the signed peer info
if !nr.operate(|e| e.has_valid_signed_node_info()) {
warn!(
"bootstrap at {:?} did not return valid signed node info",
nr
);
// xxx: delete the node?
} else {
// otherwise this bootstrap is valid, lets ask it to find ourselves now
this.reverse_find_node(nr, true).await
}
});
}
while unord.next().await.is_some() {}
Ok(())
@@ -749,7 +787,7 @@ impl RoutingTable {
nr,
entry.state_debug_info(cur_ts)
);
intf::spawn_local(rpc.clone().rpc_call_info(nr)).detach();
intf::spawn_local(rpc.clone().rpc_call_status(nr)).detach();
}
}
}

View File

@@ -63,7 +63,7 @@ impl NodeRef {
self.routing_table.operate_on_bucket_entry(self.node_id, f)
}
pub fn peer_info(&self) -> PeerInfo {
pub fn peer_info(&self) -> Option<PeerInfo> {
self.operate(|e| e.peer_info(self.node_id()))
}
pub fn has_seen_our_node_info(&self) -> bool {
@@ -72,23 +72,24 @@ impl NodeRef {
pub fn set_seen_our_node_info(&self) {
self.operate(|e| e.set_seen_our_node_info(true));
}
pub fn network_class(&self) -> NetworkClass {
self.operate(|e| e.node_info().network_class)
pub fn network_class(&self) -> Option<NetworkClass> {
self.operate(|e| e.node_info().map(|n| n.network_class))
}
pub fn outbound_protocols(&self) -> ProtocolSet {
self.operate(|e| e.node_info().outbound_protocols)
pub fn outbound_protocols(&self) -> Option<ProtocolSet> {
self.operate(|e| e.node_info().map(|n| n.outbound_protocols))
}
pub fn relay(&self) -> Option<NodeRef> {
let target_rpi = self.operate(|e| e.node_info().relay_peer_info.clone())?;
self.routing_table
.register_node_with_node_info(target_rpi.node_id.key, target_rpi.node_info)
.map_err(logthru_rtab!(error))
.ok()
.map(|mut nr| {
nr.set_filter(self.filter_ref().cloned());
nr
})
let target_rpi = self.operate(|e| e.node_info().map(|n| n.relay_peer_info))?;
target_rpi.and_then(|t| {
self.routing_table
.register_node_with_signed_node_info(t.node_id.key, t.signed_node_info)
.map_err(logthru_rtab!(error))
.ok()
.map(|mut nr| {
nr.set_filter(self.filter_ref().cloned());
nr
})
})
}
pub fn first_filtered_dial_info_detail(
&self,
@@ -105,8 +106,8 @@ impl NodeRef {
PeerScope::All | PeerScope::Local
)
{
e.local_node_info()
.first_filtered_dial_info(|di| {
e.local_node_info().and_then(|l| {
l.first_filtered_dial_info(|di| {
if let Some(filter) = self.filter.as_ref() {
di.matches_filter(filter)
} else {
@@ -117,6 +118,7 @@ impl NodeRef {
class: DialInfoClass::Direct,
dial_info: di,
})
})
} else {
None
}
@@ -130,12 +132,14 @@ impl NodeRef {
PeerScope::All | PeerScope::Global
)
{
e.node_info().first_filtered_dial_info_detail(|did| {
if let Some(filter) = self.filter.as_ref() {
did.matches_filter(filter)
} else {
true
}
e.node_info().and_then(|n| {
n.first_filtered_dial_info_detail(|did| {
if let Some(filter) = self.filter.as_ref() {
did.matches_filter(filter)
} else {
true
}
})
})
} else {
None
@@ -160,17 +164,19 @@ impl NodeRef {
PeerScope::All | PeerScope::Local
)
{
for di in e.local_node_info().all_filtered_dial_info(|di| {
if let Some(filter) = self.filter.as_ref() {
di.matches_filter(filter)
} else {
true
if let Some(lni) = e.local_node_info() {
for di in lni.all_filtered_dial_info(|di| {
if let Some(filter) = self.filter.as_ref() {
di.matches_filter(filter)
} else {
true
}
}) {
out.push(DialInfoDetail {
class: DialInfoClass::Direct,
dial_info: di,
});
}
}) {
out.push(DialInfoDetail {
class: DialInfoClass::Direct,
dial_info: di,
});
}
}
if (routing_domain == None || routing_domain == Some(RoutingDomain::PublicInternet))
@@ -182,13 +188,15 @@ impl NodeRef {
PeerScope::All | PeerScope::Global
)
{
out.append(&mut e.node_info().all_filtered_dial_info_details(|did| {
if let Some(filter) = self.filter.as_ref() {
did.matches_filter(filter)
} else {
true
}
}))
if let Some(ni) = e.node_info() {
out.append(&mut ni.all_filtered_dial_info_details(|did| {
if let Some(filter) = self.filter.as_ref() {
did.matches_filter(filter)
} else {
true
}
}))
}
}
});
out.remove_duplicates();
@@ -225,7 +233,14 @@ impl NodeRef {
}
pub fn has_any_dial_info(&self) -> bool {
self.operate(|e| e.node_info().has_any_dial_info() || e.local_node_info().has_dial_info())
self.operate(|e| {
e.node_info()
.map(|n| n.has_any_dial_info())
.unwrap_or(false)
|| e.local_node_info()
.map(|l| l.has_dial_info())
.unwrap_or(false)
})
}
}