diff --git a/veilid-core/src/routing_table/route_spec_store/route_set_spec_detail.rs b/veilid-core/src/routing_table/route_spec_store/route_set_spec_detail.rs index fd6a39ae..2b3ec72e 100644 --- a/veilid-core/src/routing_table/route_spec_store/route_set_spec_detail.rs +++ b/veilid-core/src/routing_table/route_spec_store/route_set_spec_detail.rs @@ -90,6 +90,14 @@ impl RouteSetSpecDetail { Sequencing::EnsureOrdered => self.can_do_sequenced, } } + pub fn contains_nodes(&self, nodes: &[TypedKey]) -> bool { + for h in self.hop_node_refs { + if h.node_ids().contains_any(nodes) { + return true; + } + } + false + } /// Generate a key for the cache that can be used to uniquely identify this route's contents pub fn make_cache_key(&self) -> Vec { diff --git a/veilid-core/src/routing_table/route_spec_store/route_spec_store.rs b/veilid-core/src/routing_table/route_spec_store/route_spec_store.rs index 453afa34..bd9f0c3e 100644 --- a/veilid-core/src/routing_table/route_spec_store/route_spec_store.rs +++ b/veilid-core/src/routing_table/route_spec_store/route_spec_store.rs @@ -537,7 +537,7 @@ impl RouteSpecStore { last_hop_id: PublicKey, callback: F, ) -> Option - where F: FnOnce(&RouteSpecDetail) -> R, + where F: FnOnce(&RouteSetSpecDetail, &RouteSpecDetail) -> R, R: fmt::Debug, { let inner = &*self.inner.lock(); @@ -585,7 +585,7 @@ impl RouteSpecStore { } } // We got the correct signatures, return a key and response safety spec - Some(callback(rsd)) + Some(callback(rssd, rsd)) } #[instrument(level = "trace", skip(self), ret, err)] @@ -593,15 +593,22 @@ impl RouteSpecStore { // Make loopback route to test with let dest = { - // Match the private route's hop length for safety route length - let hop_count = { + // Get the best private route for this id + let (key, hop_count) = { let inner = &mut *self.inner.lock(); let Some(rssd) = inner.content.get_detail(&private_route_id) else { bail!("route id not allocated"); }; - rssd.hop_count() + let Some(key) = rssd.get_best_route_set_key() else { + bail!("no best key to test allocated route"); + }; + // Match the private route's hop length for safety route length + let hop_count = rssd.hop_count(); + (key, hop_count) }; + // Get the private route to send to + let private_route = self.assemble_private_route(&key, None)?; // Always test routes with safety routes that are more likely to succeed let stability = Stability::Reliable; // Routes can test with whatever sequencing they were allocated with @@ -639,6 +646,12 @@ impl RouteSpecStore { // Make private route test let dest = { + + // Get the route to test + let Some(private_route) = self.best_remote_private_route(&private_route_id) else { + bail!("no best key to test remote route"); + }; + // Get a safety route that is good enough let safety_spec = SafetySpec { preferred_route: None, @@ -722,7 +735,7 @@ impl RouteSpecStore { stability: Stability, sequencing: Sequencing, directions: DirectionSet, - avoid_node_ids: &[PublicKey], + avoid_nodes: &[TypedKey], ) -> Option { let cur_ts = get_aligned_timestamp(); @@ -740,7 +753,7 @@ impl RouteSpecStore { { let mut avoid = false; for h in &detail.1.hops { - if avoid_node_ids.contains(h) { + if avoid_nodes.contains(h) { avoid = true; break; } @@ -1054,7 +1067,7 @@ impl RouteSpecStore { Ok(Some(compiled_route)) } - /// Get a route that matches a particular safety spec + /// Get an allocated route that matches a particular safety spec #[instrument(level = "trace", skip(self, inner, rti), ret, err)] fn get_route_for_safety_spec_inner( &self, @@ -1076,12 +1089,12 @@ impl RouteSpecStore { // See if the preferred route is here if let Some(preferred_route) = safety_spec.preferred_route { - if let Some(preferred_rsd) = inner.content.details.get(&preferred_route) { + if let Some(preferred_rssd) = inner.content.get_detail(&preferred_route) { // Only use the preferred route if it has the desire crypto kind - if preferred_rsd.crypto_kind == crypto_kind { - // Only use the preferred route if it doesn't end with the avoid nodes - if !avoid_nodes.contains(&TypedKey::new(crypto_kind, preferred_rsd.hops.last().cloned().unwrap())) { - return Ok(Some(preferred_route)); + if let Some(preferred_key) = preferred_rssd.get_route_set_keys().get(crypto_kind) { + // Only use the preferred route if it doesn't contain the avoid nodes + if !preferred_rssd.contains_nodes(avoid_nodes) { + return Ok(Some(preferred_key.key)); } } } @@ -1095,7 +1108,7 @@ impl RouteSpecStore { safety_spec.stability, safety_spec.sequencing, direction, - avoid_node_ids, + avoid_nodes, ) { // Found a route to use sr_pubkey @@ -1105,11 +1118,12 @@ impl RouteSpecStore { .allocate_route_inner( inner, rti, + crypto_kind, ??? safety_spec.stability, safety_spec.sequencing, safety_spec.hop_count, direction, - avoid_node_ids, + avoid_nodes, ) .map_err(RPCError::internal)? { diff --git a/veilid-core/src/rpc_processor/rpc_route.rs b/veilid-core/src/rpc_processor/rpc_route.rs index 5c7c1d0c..3d00c8e1 100644 --- a/veilid-core/src/rpc_processor/rpc_route.rs +++ b/veilid-core/src/rpc_processor/rpc_route.rs @@ -194,7 +194,7 @@ impl RPCProcessor { sender_id, |rsd| { ( - rsd.get_secret_key(), + rsd.secret_key, SafetySpec { preferred_route: Some(pr_pubkey), hop_count: rsd.hop_count(), @@ -243,7 +243,7 @@ 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 - if pr_pubkey == self.routing_table.node_id() { + if self.routing_table.node_ids().contains(&pr_pubkey) { // The private route was a stub self.process_safety_routed_operation(detail, routed_operation, remote_sr_pubkey) } else { @@ -314,13 +314,20 @@ impl RPCProcessor { /// Decrypt route hop data and sign routed operation pub(crate) fn decrypt_private_route_hop_data(&self, route_hop_data: &RouteHopData, pr_pubkey: &TypedKey, route_operation: &mut RoutedOperation) -> Result, RPCError> { + // Get crypto kind + let crypto_kind = pr_pubkey.kind; + let Some(vcrypto) = self.crypto.get(crypto_kind) else { + return Ok(NetworkResult::invalid_message( + "private route hop data crypto is not supported", + )); + }; + // Decrypt the blob with DEC(nonce, DH(the PR's public key, this hop's secret) - let node_id_secret = self.routing_table.node_id_secret(); - let dh_secret = self - .crypto - .cached_dh(&pr_pubkey, &node_id_secret) + let node_id_secret = self.routing_table.node_id_secret(crypto_kind); + let dh_secret = vcrypto + .cached_dh(&pr_pubkey.key, &node_id_secret) .map_err(RPCError::protocol)?; - let dec_blob_data = match Crypto::decrypt_aead( + let dec_blob_data = match vcrypto.decrypt_aead( &route_hop_data.blob, &route_hop_data.nonce, &dh_secret, @@ -338,15 +345,15 @@ impl RPCProcessor { let rh_reader = dec_blob_reader .get_root::() .map_err(RPCError::protocol)?; - decode_route_hop(&rh_reader)? + decode_route_hop(&rh_reader, self.crypto.clone())? }; // Sign the operation if this is not our last hop // as the last hop is already signed by the envelope if route_hop.next_hop.is_some() { - 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) + let node_id = self.routing_table.node_id(crypto_kind); + let node_id_secret = self.routing_table.node_id_secret(crypto_kind); + let sig = vcrypto.sign(&node_id.key, &node_id_secret, &route_operation.data) .map_err(RPCError::internal)?; route_operation.signatures.push(sig); } @@ -378,25 +385,24 @@ impl RPCProcessor { _ => panic!("not a statement"), }; - // Process routed operation version - // xxx switch this to a Crypto trait factory method per issue#140 - if route.operation.version != MAX_CRYPTO_VERSION { + // Get crypto kind + let crypto_kind = route.safety_route.crypto_kind(); + let Some(vcrypto) = self.crypto.get(crypto_kind) else { return Ok(NetworkResult::invalid_message( - "routes operation crypto is not valid version", + "routed operation crypto is not supported", )); - } + }; // See what kind of safety route we have going on here match route.safety_route.hops { // There is a safety route hop SafetyRouteHops::Data(ref route_hop_data) => { // Decrypt the blob with DEC(nonce, DH(the SR's public key, this hop's secret) - let node_id_secret = self.routing_table.node_id_secret(); - let dh_secret = self - .crypto - .cached_dh(&route.safety_route.public_key, &node_id_secret) + let node_id_secret = self.routing_table.node_id_secret(crypto_kind); + let dh_secret = vcrypto + .cached_dh(&route.safety_route.public_key.key, &node_id_secret) .map_err(RPCError::protocol)?; - let mut dec_blob_data = Crypto::decrypt_aead(&route_hop_data.blob, &route_hop_data.nonce, &dh_secret, None) + let mut dec_blob_data = vcrypto.decrypt_aead(&route_hop_data.blob, &route_hop_data.nonce, &dh_secret, None) .map_err(RPCError::protocol)?; // See if this is last hop in safety route, if so, we're decoding a PrivateRoute not a RouteHop @@ -413,7 +419,7 @@ impl RPCProcessor { let pr_reader = dec_blob_reader .get_root::() .map_err(RPCError::protocol)?; - decode_private_route(&pr_reader)? + decode_private_route(&pr_reader, self.crypto.clone())? }; // Switching from full safety route to private route first hop @@ -429,7 +435,7 @@ impl RPCProcessor { let rh_reader = dec_blob_reader .get_root::() .map_err(RPCError::protocol)?; - decode_route_hop(&rh_reader)? + decode_route_hop(&rh_reader, self.crypto.clone())? }; // Continue the full safety route with another hop