From fc6eb6e84aade9d5edda24d16455a040d1d99a2b Mon Sep 17 00:00:00 2001 From: John Smith Date: Thu, 20 Oct 2022 15:09:04 -0400 Subject: [PATCH] checkpoint --- .../src/routing_table/route_spec_store.rs | 55 ++++++---- veilid-core/src/rpc_processor/mod.rs | 101 +++++++++++------- veilid-core/src/veilid_api/privacy.rs | 23 ++++ 3 files changed, 119 insertions(+), 60 deletions(-) diff --git a/veilid-core/src/routing_table/route_spec_store.rs b/veilid-core/src/routing_table/route_spec_store.rs index 5dc639d8..ef0854b2 100644 --- a/veilid-core/src/routing_table/route_spec_store.rs +++ b/veilid-core/src/routing_table/route_spec_store.rs @@ -17,9 +17,9 @@ pub struct SafetySpec { #[derive(Clone, Debug)] pub struct CompiledRoute { /// The safety route attached to the private route - safety_route: SafetyRoute, + pub safety_route: SafetyRoute, /// The secret used to encrypt the message payload - secret: DHTKeySecret, + pub secret: DHTKeySecret, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -600,7 +600,7 @@ impl RouteSpecStore { &mut self, rti: &RoutingTableInner, routing_table: RoutingTable, - safety_spec: SafetySpec, + safety_spec: Option, private_route: PrivateRoute, ) -> Result, RPCError> { let pr_hopcount = private_route.hop_count as usize; @@ -608,7 +608,18 @@ impl RouteSpecStore { return Err(RPCError::internal("private route hop count too long")); } + // See if we are using a safety route, if not, short circuit this operation + if safety_spec.is_none() { + // Safety route stub with the node's public key as the safety route key since it's the 0th hop + return Ok(Some(CompiledRoute { + safety_route: SafetyRoute::new_stub(routing_table.node_id(), private_route), + secret: routing_table.node_id_secret(), + })); + } + let safety_spec = safety_spec.unwrap(); + // See if the preferred route is here + let safety_route_public_key; let opt_safety_rsd: Option<&mut RouteSpecDetail> = if let Some(preferred_route) = safety_spec.preferred_route { self.detail_mut(&preferred_route) @@ -650,19 +661,21 @@ impl RouteSpecStore { // xxx implement caching first! - // xxx implement, ensure we handle hops == 0 for our safetyspec - // Ensure the total hop count isn't too long for our config let sr_hopcount = safety_spec.hop_count; - if sr_hopcount > self.max_route_hop_count { - return Err(RPCError::internal("private route hop count too long")); + if sr_hopcount == 0 { + return Err(RPCError::internal("safety route hop count is zero")); } - let total_hopcount = sr_hopcount + pr_hopcount; + if sr_hopcount > self.max_route_hop_count { + return Err(RPCError::internal("safety route hop count too long")); + } + + // See if we can optimize this compilation yet + // We don't want to include full nodeinfo if we don't have to + //let optimize = safety_rsd. // Create hops - let hops = if sr_hopcount == 0 { - SafetyRouteHops::Private(private_route) - } else { + let hops = { // start last blob-to-encrypt data off as private route let mut blob_data = { let mut pr_message = ::capnp::message::Builder::new_default(); @@ -681,16 +694,13 @@ impl RouteSpecStore { // (outer hop is a RouteHopData, not a RouteHop). // Each loop mutates 'nonce', and 'blob_data' let mut nonce = Crypto::get_random_nonce(); + let crypto = routing_table.network_manager().crypto(); for h in (1..sr_hopcount).rev() { // Get blob to encrypt for next hop blob_data = { // Encrypt the previous blob ENC(nonce, DH(PKhop,SKsr)) - let dh_secret = self - .crypto - .cached_dh( - &safety_route_spec.hops[h].dial_info.node_id.key, - &safety_route_spec.secret_key, - ) + let dh_secret = crypto + .cached_dh(&safety_rsd.hops[h], &safety_rsd.secret_key) .map_err(RPCError::map_internal("dh failed"))?; let enc_msg_data = Crypto::encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None) @@ -704,7 +714,7 @@ impl RouteSpecStore { // Make route hop let route_hop = RouteHop { - dial_info: safety_route_spec.hops[h].dial_info.clone(), + node: safety_route_spec.hops[h].dial_info.clone(), next_hop: Some(route_hop_data), }; @@ -744,12 +754,15 @@ impl RouteSpecStore { // Build safety route let safety_route = SafetyRoute { - public_key: safety_route_spec.public_key, - hop_count: safety_route_spec.hops.len() as u8, + public_key: safety_rsd. + hop_count: safety_spec.hop_count as u8, hops, }; - Ok(safety_route) + Ok(Some(CompiledRoute { + safety_route, + secret: todo!(), + })) } /// Mark route as published diff --git a/veilid-core/src/rpc_processor/mod.rs b/veilid-core/src/rpc_processor/mod.rs index 0edc535c..4947a0a3 100644 --- a/veilid-core/src/rpc_processor/mod.rs +++ b/veilid-core/src/rpc_processor/mod.rs @@ -21,6 +21,7 @@ mod rpc_validate_dial_info; mod rpc_value_changed; mod rpc_watch_value; +pub use coders::*; pub use destination::*; pub use operation_waiter::*; pub use rpc_error::*; @@ -29,7 +30,6 @@ use super::*; use crate::dht::*; use crate::xx::*; use capnp::message::ReaderSegments; -use coders::*; use futures_util::StreamExt; use network_manager::*; use receipt_manager::*; @@ -55,6 +55,8 @@ struct RPCMessageHeader { connection_descriptor: ConnectionDescriptor, /// The routing domain the message was sent through routing_domain: RoutingDomain, + /// The private route the message was received through + private_route: Option, } #[derive(Debug)] @@ -134,7 +136,7 @@ struct RenderedOperation { message: Vec, // The rendered operation bytes node_id: DHTKey, // Destination node id we're sending to node_ref: NodeRef, // Node to send envelope to (may not be destination node id in case of relay) - hop_count: usize, // Total safety + private route hop count + hop_count: usize, // Total safety + private route hop count + 1 hop for the initial send } ///////////////////////////////////////////////////////////////////// @@ -396,16 +398,25 @@ impl RPCProcessor { } // Wrap an operation with a private route inside a safety route - pub(super) fn wrap_with_route(xxx continue here + pub(super) fn wrap_with_route( &self, - safety_spec: SafetySpec, + safety_spec: Option, private_route: PrivateRoute, message_data: Vec, - ) -> Result { - let compiled_route: CompiledRoute = self.routing_table().with_route_spec_store(|rss| { - // Compile the safety route with the private route - rss.compile_safety_route(self.safety_spec, private_route) - })?; + ) -> Result, RPCError> { + let routing_table = self.routing_table(); + let compiled_route: CompiledRoute = + match self.routing_table().with_route_spec_store(|rss, rti| { + // Compile the safety route with the private route + rss.compile_safety_route(rti, routing_table, safety_spec, private_route) + })? { + Some(cr) => cr, + None => { + return Ok(NetworkResult::no_connection_other( + "private route could not be compiled at this time", + )) + } + }; // Encrypt routed operation // Xmsg + ENC(Xmsg, DH(PKapr, SKbsr)) @@ -421,30 +432,42 @@ impl RPCProcessor { let operation = RoutedOperation::new(nonce, enc_msg_data); // Prepare route operation - let route = RPCOperationRoute { - safety_route, + let route_operation = RPCOperationRoute { + safety_route: compiled_route.safety_route, operation, }; - let operation = - RPCOperation::new_statement(RPCStatement::new(RPCStatementDetail::Route(route)), None); + let operation = RPCOperation::new_statement( + RPCStatement::new(RPCStatementDetail::Route(route_operation)), + None, + ); // Convert message to bytes and return it let mut route_msg = ::capnp::message::Builder::new_default(); let mut route_operation = route_msg.init_root::(); operation.encode(&mut route_operation)?; - let out = builder_to_vec(route_msg)?; + let out_message = builder_to_vec(route_msg)?; - // out_node_id = sr - // .hops - // .first() - // .ok_or_else(RPCError::else_internal("no hop in safety route"))? - // .dial_info - // .node_id - // .key; + // Get the first hop this is going to + let out_node_id = compiled_route + .safety_route + .hops + .first() + .ok_or_else(RPCError::else_internal("no hop in safety route"))? + .dial_info + .node_id + .key; - //out_hop_count = 1 + sr.hops.len(); + let out_hop_count = + (1 + compiled_route.safety_route.hop_count + private_route.hop_count) as usize; - Ok(out) + let out = RenderedOperation { + message: out_message, + node_id: out_node_id, + node_ref: compiled_route.first_hop, + hop_count: out_hop_count, + }; + + Ok(NetworkResult::value(out)) } /// Produce a byte buffer that represents the wire encoding of the entire @@ -455,8 +478,8 @@ impl RPCProcessor { &self, dest: Destination, operation: &RPCOperation, - ) -> Result { - let out: RenderedOperation; + ) -> Result, RPCError> { + let out: NetworkResult; // Encode message to a builder and make a message reader for it // Then produce the message as an unencrypted byte buffer @@ -471,12 +494,12 @@ impl RPCProcessor { match dest { Destination::Direct { target: ref node_ref, - safety, + safety_spec, } | Destination::Relay { relay: ref node_ref, target: _, - safety, + safety_spec, } => { // Send to a node without a private route // -------------------------------------- @@ -485,7 +508,7 @@ impl RPCProcessor { let (node_ref, node_id) = if let Destination::Relay { relay: _, target: ref dht_key, - safety: _, + safety_spec: _, } = dest { (node_ref.clone(), dht_key.clone()) @@ -495,36 +518,36 @@ impl RPCProcessor { }; // Handle the existence of safety route - match safety { - false => { + match safety_spec { + None => { // If no safety route is being used, and we're not sending to a private // route, we can use a direct envelope instead of routing - out = RenderedOperation { + out = NetworkResult::value(RenderedOperation { message, node_id, node_ref, hop_count: 1, - }; + }); } - true => { + Some(safety_spec) => { // No private route was specified for the request // but we are using a safety route, so we must create an empty private route let private_route = PrivateRoute::new_stub(node_id); // Wrap with safety route - out = self.wrap_with_route(true, private_route, message)?; + out = self.wrap_with_route(Some(safety_spec), private_route, message)?; } }; } Destination::PrivateRoute { private_route, - safety, + safety_spec, reliable, } => { // Send to private route // --------------------- // Reply with 'route' operation - out = self.wrap_with_route(safety, private_route, message)?; + out = self.wrap_with_route(safety_spec, private_route, message)?; } } @@ -602,7 +625,7 @@ impl RPCProcessor { node_id, node_ref, hop_count, - } = self.render_operation(dest, &operation)?; + } = network_result_try!(self.render_operation(dest, &operation)?); // Calculate answer timeout // Timeout is number of hops times the timeout per hop @@ -665,7 +688,7 @@ impl RPCProcessor { node_id, node_ref, hop_count: _, - } = self.render_operation(dest, &operation)?; + } = network_result_try!(self.render_operation(dest, &operation)?); // Send statement let bytes = message.len() as u64; @@ -749,7 +772,7 @@ impl RPCProcessor { node_id, node_ref, hop_count: _, - } = self.render_operation(dest, &operation)?; + } = network_result_try!(self.render_operation(dest, &operation)?); // Send the reply let bytes = message.len() as u64; diff --git a/veilid-core/src/veilid_api/privacy.rs b/veilid-core/src/veilid_api/privacy.rs index dafd0c25..9bdd05f8 100644 --- a/veilid-core/src/veilid_api/privacy.rs +++ b/veilid-core/src/veilid_api/privacy.rs @@ -48,6 +48,19 @@ impl PrivateRoute { first_hop: None, } } + pub fn simplify(self) -> Self { + Self { + public_key: self.public_key, + hop_count: self.hop_count, + first_hop: self.first_hop.map(|h| RouteHop { + node: match h.node { + RouteNode::NodeId(ni) => RouteNode::NodeId(ni), + RouteNode::PeerInfo(pi) => RouteNode::NodeId(pi.node_id), + }, + next_hop: h.next_hop, + }), + } + } } impl fmt::Display for PrivateRoute { @@ -79,6 +92,16 @@ pub struct SafetyRoute { pub hops: SafetyRouteHops, } +impl SafetyRoute { + pub fn new_stub(public_key: DHTKey, private_route: PrivateRoute) -> Self { + Self { + public_key, + hop_count: 0, + hops: SafetyRouteHops::Private(private_route), + } + } +} + impl fmt::Display for SafetyRoute { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(