private route work
This commit is contained in:
@@ -171,7 +171,6 @@ pub struct RPCProcessorUnlockedInner {
|
||||
queue_size: u32,
|
||||
concurrency: u32,
|
||||
max_route_hop_count: usize,
|
||||
default_route_hop_count: usize,
|
||||
validate_dial_info_receipt_time_ms: u32,
|
||||
update_callback: UpdateCallback,
|
||||
waiting_rpc_table: OperationWaiter<RPCMessage>,
|
||||
@@ -208,7 +207,6 @@ impl RPCProcessor {
|
||||
let queue_size = c.network.rpc.queue_size;
|
||||
let timeout = ms_to_us(c.network.rpc.timeout_ms);
|
||||
let max_route_hop_count = c.network.rpc.max_route_hop_count as usize;
|
||||
let default_route_hop_count = c.network.rpc.default_route_hop_count as usize;
|
||||
if concurrency == 0 {
|
||||
concurrency = intf::get_concurrency() / 2;
|
||||
if concurrency == 0 {
|
||||
@@ -222,7 +220,6 @@ impl RPCProcessor {
|
||||
queue_size,
|
||||
concurrency,
|
||||
max_route_hop_count,
|
||||
default_route_hop_count,
|
||||
validate_dial_info_receipt_time_ms,
|
||||
update_callback,
|
||||
waiting_rpc_table: OperationWaiter::new(),
|
||||
@@ -418,7 +415,7 @@ impl RPCProcessor {
|
||||
}
|
||||
|
||||
// Wrap an operation with a private route inside a safety route
|
||||
pub(super) fn wrap_with_route(
|
||||
fn wrap_with_route(
|
||||
&self,
|
||||
safety_selection: SafetySelection,
|
||||
private_route: PrivateRoute,
|
||||
@@ -540,6 +537,7 @@ impl RPCProcessor {
|
||||
match safety_selection {
|
||||
SafetySelection::Unsafe(sequencing) => {
|
||||
// Apply safety selection sequencing requirement if it is more strict than the node_ref's sequencing requirement
|
||||
let mut node_ref = node_ref.clone();
|
||||
if sequencing > node_ref.sequencing() {
|
||||
node_ref.set_sequencing(sequencing)
|
||||
}
|
||||
|
@@ -62,22 +62,26 @@ impl RPCProcessor {
|
||||
|
||||
// add node information for the requesting node to our routing table
|
||||
let routing_table = self.routing_table();
|
||||
let network_manager = self.network_manager();
|
||||
let has_valid_own_node_info =
|
||||
routing_table.has_valid_own_node_info(RoutingDomain::PublicInternet);
|
||||
let own_peer_info = routing_table.get_own_peer_info(RoutingDomain::PublicInternet);
|
||||
|
||||
// find N nodes closest to the target node in our routing table
|
||||
let closest_nodes = routing_table.find_closest_nodes(
|
||||
find_node_q.node_id,
|
||||
// filter
|
||||
|rti, _k, v| {
|
||||
|
||||
let filter = Box::new(
|
||||
move |rti: &RoutingTableInner, _k: DHTKey, v: Option<Arc<BucketEntry>>| {
|
||||
rti.filter_has_valid_signed_node_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
has_valid_own_node_info,
|
||||
v,
|
||||
)
|
||||
},
|
||||
) as RoutingTableEntryFilter;
|
||||
let filters = VecDeque::from([filter]);
|
||||
|
||||
let closest_nodes = routing_table.find_closest_nodes(
|
||||
find_node_q.node_id,
|
||||
filters,
|
||||
// transform
|
||||
|rti, k, v| {
|
||||
rti.transform_to_peer_info(
|
||||
|
@@ -45,7 +45,7 @@ impl RPCProcessor {
|
||||
RPCMessageHeaderDetail::PrivateRoute(detail) => {
|
||||
network_result_value_or_log!(debug
|
||||
network_manager
|
||||
.handle_private_receipt(receipt)
|
||||
.handle_private_receipt(receipt, detail.private_route)
|
||||
.await => {}
|
||||
);
|
||||
}
|
||||
|
@@ -121,7 +121,8 @@ impl RPCProcessor {
|
||||
if next_private_route.hop_count != 0 {
|
||||
let node_id = self.routing_table.node_id();
|
||||
let node_id_secret = self.routing_table.node_id_secret();
|
||||
let sig = sign(&node_id, &node_id_secret, &route.operation.data).map_err(RPCError::internal)?;
|
||||
let sig = sign(&node_id, &node_id_secret, &route.operation.data)
|
||||
.map_err(RPCError::internal)?;
|
||||
route.operation.signatures.push(sig);
|
||||
}
|
||||
|
||||
@@ -169,14 +170,16 @@ impl RPCProcessor {
|
||||
|
||||
// If the private route public key is our node id, then this was sent via safety route to our node directly
|
||||
// so there will be no signatures to validate
|
||||
let opt_pr_info = if private_route.public_key == self.routing_table.node_id() {
|
||||
let (secret_key, safety_selection) = if private_route.public_key
|
||||
== self.routing_table.node_id()
|
||||
{
|
||||
// The private route was a stub
|
||||
// Return our secret key and an appropriate safety selection
|
||||
//
|
||||
// Note: it is important that we never respond with a safety route to questions that come
|
||||
// in without a private route. Giving away a safety route when the node id is known is
|
||||
// in without a private route. Giving away a safety route when the node id is known is
|
||||
// a privacy violation!
|
||||
|
||||
|
||||
// Get sequencing preference
|
||||
let sequencing = if detail
|
||||
.connection_descriptor
|
||||
@@ -187,65 +190,25 @@ impl RPCProcessor {
|
||||
} else {
|
||||
Sequencing::NoPreference
|
||||
};
|
||||
Some((
|
||||
self.routing_table.node_id_secret(),
|
||||
(
|
||||
self.routing_table.node_id_secret(),
|
||||
SafetySelection::Unsafe(sequencing),
|
||||
))
|
||||
)
|
||||
} else {
|
||||
// Get sender id
|
||||
let sender_id = detail.envelope.get_sender_id();
|
||||
|
||||
// Look up the private route and ensure it's one in our spec store
|
||||
let rss= self.routing_table.route_spec_store();
|
||||
let opt_signatures_valid = rss.with_route_spec_detail(&private_route.public_key, |rsd| {
|
||||
// Ensure we have the right number of signatures
|
||||
if routed_operation.signatures.len() != rsd.hops.len() - 1 {
|
||||
// Wrong number of signatures
|
||||
log_rpc!(debug "wrong number of signatures ({} should be {}) for routed operation on private route {}", routed_operation.signatures.len(), rsd.hops.len() - 1, private_route.public_key);
|
||||
return None;
|
||||
}
|
||||
// Validate signatures to ensure the route was handled by the nodes and not messed with
|
||||
for (hop_n, hop_public_key) in rsd.hops.iter().enumerate() {
|
||||
// The last hop is not signed, as the whole packet is signed
|
||||
if hop_n == routed_operation.signatures.len() {
|
||||
// Verify the node we received the routed operation from is the last hop in our route
|
||||
if *hop_public_key != sender_id {
|
||||
log_rpc!(debug "received routed operation from the wrong hop ({} should be {}) on private route {}", hop_public_key.encode(), sender_id.encode(), private_route.public_key);
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
// Verify a signature for a hop node along the route
|
||||
if let Err(e) = verify(
|
||||
hop_public_key,
|
||||
&routed_operation.data,
|
||||
&routed_operation.signatures[hop_n],
|
||||
) {
|
||||
log_rpc!(debug "failed to verify signature for hop {} at {} on private route {}", hop_n, hop_public_key, private_route.public_key);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We got the correct signatures, return a key ans
|
||||
Some((
|
||||
rsd.secret_key,
|
||||
SafetySelection::Safe(SafetySpec {
|
||||
preferred_route: Some(private_route.public_key),
|
||||
hop_count: rsd.hops.len(),
|
||||
stability: rsd.stability,
|
||||
sequencing: rsd.sequencing,
|
||||
})
|
||||
))
|
||||
});
|
||||
opt_signatures_valid.ok_or_else(|| {
|
||||
RPCError::protocol("routed operation received on unallocated private route")
|
||||
})?
|
||||
let rss = self.routing_table.route_spec_store();
|
||||
rss.validate_signatures(
|
||||
&private_route.public_key,
|
||||
&routed_operation.signatures,
|
||||
&routed_operation.data,
|
||||
sender_id,
|
||||
)
|
||||
.map_err(RPCError::protocol)?
|
||||
.ok_or_else(|| RPCError::protocol("signatures did not validate for private route"))?
|
||||
};
|
||||
if opt_pr_info.is_none() {
|
||||
return Err(RPCError::protocol(
|
||||
"signatures did not validate for private route",
|
||||
));
|
||||
}
|
||||
let (secret_key, safety_selection) = opt_pr_info.unwrap();
|
||||
|
||||
// Now that things are valid, decrypt the routed operation with DEC(nonce, DH(the SR's public key, the PR's (or node's) secret)
|
||||
// xxx: punish nodes that send messages that fail to decrypt eventually
|
||||
@@ -344,8 +307,13 @@ impl RPCProcessor {
|
||||
.await?;
|
||||
} else {
|
||||
// Private route is empty, process routed operation
|
||||
self.process_routed_operation(detail, route.operation, &route.safety_route, &private_route)
|
||||
.await?;
|
||||
self.process_routed_operation(
|
||||
detail,
|
||||
route.operation,
|
||||
&route.safety_route,
|
||||
&private_route,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
} else if blob_tag == 0 {
|
||||
// RouteHop
|
||||
@@ -410,8 +378,13 @@ impl RPCProcessor {
|
||||
.await?;
|
||||
} else {
|
||||
// No hops left, time to process the routed operation
|
||||
self.process_routed_operation(detail, route.operation, &route.safety_route, private_route)
|
||||
.await?;
|
||||
self.process_routed_operation(
|
||||
detail,
|
||||
route.operation,
|
||||
&route.safety_route,
|
||||
private_route,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -34,7 +34,8 @@ impl RPCProcessor {
|
||||
|
||||
// Wait for receipt
|
||||
match eventual_value.await.take_value().unwrap() {
|
||||
ReceiptEvent::ReturnedPrivate | ReceiptEvent::ReturnedInBand { inbound_noderef: _ } => {
|
||||
ReceiptEvent::ReturnedPrivate { private_route: _ }
|
||||
| ReceiptEvent::ReturnedInBand { inbound_noderef: _ } => {
|
||||
log_net!(debug "validate_dial_info receipt should be returned out-of-band".green());
|
||||
Ok(false)
|
||||
}
|
||||
@@ -94,20 +95,26 @@ impl RPCProcessor {
|
||||
routing_domain,
|
||||
dial_info.clone(),
|
||||
);
|
||||
let will_validate_dial_info_filter = Box::new(move |_rti, e: &BucketEntryInner| {
|
||||
if let Some(status) = &e.node_status(routing_domain) {
|
||||
status.will_validate_dial_info()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
let filter = RoutingTable::combine_entry_filters(
|
||||
let will_validate_dial_info_filter = Box::new(
|
||||
move |rti: &RoutingTableInner, _k: DHTKey, v: Option<Arc<BucketEntry>>| {
|
||||
let entry = v.unwrap();
|
||||
entry.with(rti, move |_rti, e| {
|
||||
if let Some(status) = &e.node_status(routing_domain) {
|
||||
status.will_validate_dial_info()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
},
|
||||
) as RoutingTableEntryFilter;
|
||||
|
||||
let filters = VecDeque::from([
|
||||
outbound_dial_info_entry_filter,
|
||||
will_validate_dial_info_filter, fuck this shit. do it tomorrow.
|
||||
);
|
||||
will_validate_dial_info_filter,
|
||||
]);
|
||||
|
||||
// Find nodes matching filter to redirect this to
|
||||
let peers = routing_table.find_fast_public_nodes_filtered(node_count, filter);
|
||||
let peers = routing_table.find_fast_public_nodes_filtered(node_count, filters);
|
||||
if peers.is_empty() {
|
||||
return Err(RPCError::internal(format!(
|
||||
"no peers able to reach dialinfo '{:?}'",
|
||||
|
Reference in New Issue
Block a user