diff --git a/veilid-core/proto/veilid.capnp b/veilid-core/proto/veilid.capnp index a09da6f9..dfec750e 100644 --- a/veilid-core/proto/veilid.capnp +++ b/veilid-core/proto/veilid.capnp @@ -529,7 +529,7 @@ struct Answer @0xacacb8b6988c1058 { struct Operation @0xbf2811c435403c3b { opId @0 :UInt64; # Random RPC ID. Must be random to foil reply forgery attacks. - senderNodeInfo @1 :SignedNodeInfo; # (optional) SignedNodeInfo for the sender to be cached by the receiver. + senderPeerInfo @1 :PeerInfo; # (optional) PeerInfo for the sender to be cached by the receiver. targetNodeInfoTs @2 :UInt64; # Timestamp the sender believes the target's node info to be at or zero if not sent kind :union { question @3 :Question; diff --git a/veilid-core/src/crypto/types.rs b/veilid-core/src/crypto/types.rs index a6334ee6..49e37f4a 100644 --- a/veilid-core/src/crypto/types.rs +++ b/veilid-core/src/crypto/types.rs @@ -159,6 +159,13 @@ impl TypedKeySet { out.sort_by(compare_crypto_kind); out } + pub fn keys(&self) -> Vec { + let mut out = Vec::new(); + for tk in &self.items { + out.push(tk.key); + } + out + } pub fn get(&self, kind: CryptoKind) -> Option { self.items.iter().find(|x| x.kind == kind).copied() } diff --git a/veilid-core/src/network_manager/mod.rs b/veilid-core/src/network_manager/mod.rs index a8bdb7c2..dc25da2e 100644 --- a/veilid-core/src/network_manager/mod.rs +++ b/veilid-core/src/network_manager/mod.rs @@ -765,34 +765,33 @@ impl NetworkManager { /// Called by the RPC handler when we want to issue an RPC request or response /// node_ref is the direct destination to which the envelope will be sent - /// If 'envelope_node_id' is specified, it can be different than the node_ref being sent to + /// If 'envelope_node_ref' is specified, it can be different than the node_ref being sent to /// which will cause the envelope to be relayed #[instrument(level = "trace", skip(self, body), ret, err)] pub async fn send_envelope>( &self, node_ref: NodeRef, - envelope_node_id: Option, + envelope_node_ref: Option, body: B, ) -> EyreResult> { - let via_node_ids = node_ref.node_ids(); - let Some(best_via_node_id) = via_node_ids.best() else { - bail!("should have a best node id"); - }; - let envelope_node_id = envelope_node_id.unwrap_or(best_via_node_id); - if !via_node_ids.contains(&envelope_node_id) { + let end_node_ref = envelope_node_ref.as_ref().unwrap_or(&node_ref).clone(); + + if !node_ref.same_entry(&end_node_ref) { log_net!( "sending envelope to {:?} via {:?}", - envelope_node_id, + end_node_ref, node_ref ); } else { log_net!("sending envelope to {:?}", node_ref); } + let best_node_id = end_node_ref.best_node_id(); + // Get node's envelope versions and see if we can send to it // and if so, get the max version we can use - let Some(envelope_version) = node_ref.envelope_support().into_iter().rev().find(|x| VALID_ENVELOPE_VERSIONS.contains(x)) else { + let Some(envelope_version) = end_node_ref.best_envelope_version() else { bail!( "can't talk to this node {} because we dont support its envelope versions", node_ref @@ -800,10 +799,10 @@ impl NetworkManager { }; // Build the envelope to send - let out = self.build_envelope(envelope_node_id, envelope_version, body)?; + let out = self.build_envelope(best_node_id, envelope_version, body)?; // Send the envelope via whatever means necessary - self.send_data(node_ref.clone(), out).await + self.send_data(node_ref, out).await } /// Called by the RPC handler when we want to issue an direct receipt @@ -867,7 +866,7 @@ impl NetworkManager { let rpc = self.rpc_processor(); network_result_try!(rpc .rpc_call_signal( - Destination::relay(relay_nr, target_nr.node_id()), + Destination::relay(relay_nr, target_nr.clone()), SignalInfo::ReverseConnect { receipt, peer_info }, ) .await @@ -972,7 +971,7 @@ impl NetworkManager { let rpc = self.rpc_processor(); network_result_try!(rpc .rpc_call_signal( - Destination::relay(relay_nr, target_nr.node_id()), + Destination::relay(relay_nr, target_nr.clone()), SignalInfo::HolePunch { receipt, peer_info }, ) .await @@ -1076,7 +1075,7 @@ impl NetworkManager { let relay_nr = routing_table .lookup_and_filter_noderef(relay_key, routing_domain.into(), dial_info_filter) .ok_or_else(|| eyre!("couldn't look up relay"))?; - if target_node_ref.node_id() != target_key { + if !target_node_ref.node_ids().contains(&target_key) { bail!("target noderef didn't match target key"); } NodeContactMethod::SignalReverse(relay_nr, target_node_ref) @@ -1085,7 +1084,7 @@ impl NetworkManager { let relay_nr = routing_table .lookup_and_filter_noderef(relay_key, routing_domain.into(), dial_info_filter) .ok_or_else(|| eyre!("couldn't look up relay"))?; - if target_node_ref.node_id() != target_key { + if target_node_ref.node_ids().contains(&target_key) { bail!("target noderef didn't match target key"); } NodeContactMethod::SignalHolePunch(relay_nr, target_node_ref) @@ -1386,7 +1385,7 @@ impl NetworkManager { let some_relay_nr = if self.check_client_whitelist(sender_id) { // Full relay allowed, do a full resolve_node - match rpc.resolve_node(recipient_id).await { + match rpc.resolve_node(recipient_id.key).await { Ok(v) => v, Err(e) => { log_net!(debug "failed to resolve recipient node for relay, dropping outbound relayed packet: {}" ,e); diff --git a/veilid-core/src/routing_table/bucket_entry.rs b/veilid-core/src/routing_table/bucket_entry.rs index 2058fb24..1b2c52ef 100644 --- a/veilid-core/src/routing_table/bucket_entry.rs +++ b/veilid-core/src/routing_table/bucket_entry.rs @@ -476,6 +476,10 @@ impl BucketEntryInner { self.envelope_support.clone() } + pub fn best_envelope_version(&self) -> Option { + self.envelope_support.iter().rev().find(|x| VALID_ENVELOPE_VERSIONS.contains(x)).copied() + } + pub fn state(&self, cur_ts: Timestamp) -> BucketEntryState { if self.check_reliable(cur_ts) { BucketEntryState::Reliable diff --git a/veilid-core/src/routing_table/node_ref.rs b/veilid-core/src/routing_table/node_ref.rs index 45dbff36..a00d014f 100644 --- a/veilid-core/src/routing_table/node_ref.rs +++ b/veilid-core/src/routing_table/node_ref.rs @@ -132,6 +132,9 @@ pub trait NodeRefBase: Sized { fn set_envelope_support(&self, envelope_support: Vec) { self.operate_mut(|_rti, e| e.set_envelope_support(envelope_support)) } + fn best_envelope_version(&self) -> Option { + self.operate(|_rti, e| e.best_envelope_version()) + } fn state(&self, cur_ts: Timestamp) -> BucketEntryState { self.operate(|_rti, e| e.state(cur_ts)) } diff --git a/veilid-core/src/routing_table/privacy.rs b/veilid-core/src/routing_table/privacy.rs index 75a9ea3d..232a39e5 100644 --- a/veilid-core/src/routing_table/privacy.rs +++ b/veilid-core/src/routing_table/privacy.rs @@ -16,7 +16,7 @@ pub struct RouteHopData { #[derive(Clone, Debug)] pub enum RouteNode { /// Route node is optimized, no contact method information as this node id has been seen before - NodeId(TypedKey), + NodeId(PublicKey), /// Route node with full contact method information to ensure the peer is reachable PeerInfo(PeerInfo), } @@ -79,6 +79,11 @@ impl PrivateRoute { false } + /// Get the crypto kind in use for this route + pub fn crypto_kind(&self) -> CryptoKind { + self.public_key.kind + } + /// Remove the first unencrypted hop if possible pub fn pop_first_hop(&mut self) -> Option { match &mut self.hops { @@ -112,8 +117,8 @@ impl PrivateRoute { // Get the safety route to use from the spec Some(match &pr_first_hop.node { - RouteNode::NodeId(n) => n, - RouteNode::PeerInfo(p) => p.node_id.key, + RouteNode::NodeId(n) => TypedKey::new(self.public_key.kind, *n), + RouteNode::PeerInfo(p) => p.node_ids.get(self.public_key.kind).unwrap(), }) } } @@ -126,8 +131,13 @@ impl fmt::Display for PrivateRoute { self.public_key, self.hop_count, match &self.hops { - PrivateRouteHops::FirstHop(fh) => { - format!("->{}", fh.node) + PrivateRouteHops::FirstHop(_) => { + format!( + "->{}", + self.first_hop_node_id() + .map(|n| n.to_string()) + .unwrap_or_else(|| "None".to_owned()) + ) } PrivateRouteHops::Data(_) => { "->?".to_owned() @@ -156,6 +166,7 @@ pub struct SafetyRoute { } impl SafetyRoute { + /// Stub route is the form used when no privacy is required, but you need to directly contact a private route pub fn new_stub(public_key: TypedKey, private_route: PrivateRoute) -> Self { // First hop should have already been popped off for stubbed safety routes since // we are sending directly to the first hop @@ -166,9 +177,16 @@ impl SafetyRoute { hops: SafetyRouteHops::Private(private_route), } } + + /// Check if this is a stub route pub fn is_stub(&self) -> bool { matches!(self.hops, SafetyRouteHops::Private(_)) } + + /// Get the crypto kind in use for this route + pub fn crypto_kind(&self) -> CryptoKind { + self.public_key.kind + } } impl fmt::Display for SafetyRoute { diff --git a/veilid-core/src/routing_table/route_spec_store.rs b/veilid-core/src/routing_table/route_spec_store.rs index ab3280ca..cc03a7d9 100644 --- a/veilid-core/src/routing_table/route_spec_store.rs +++ b/veilid-core/src/routing_table/route_spec_store.rs @@ -163,6 +163,8 @@ impl RouteStats { #[derive(Clone, Debug, RkyvArchive, RkyvSerialize, RkyvDeserialize)] #[archive_attr(repr(C), derive(CheckBytes))] pub struct RouteSpecDetail { + /// Crypto kind + crypto_kind: CryptoKind, /// Secret key #[with(Skip)] secret_key: SecretKey, @@ -187,6 +189,9 @@ pub struct RouteSpecDetail { } impl RouteSpecDetail { + pub fn get_crypto_kind(&self) -> CryptoKind { + self.crypto_kind + } pub fn get_stats(&self) -> &RouteStats { &self.stats } @@ -221,13 +226,13 @@ impl RouteSpecDetail { #[archive_attr(repr(C, align(8)), derive(CheckBytes))] pub struct RouteSpecStoreContent { /// All of the routes we have allocated so far - details: HashMap, + details: HashMap, } /// What remote private routes have seen #[derive(Debug, Clone, Default)] pub struct RemotePrivateRouteInfo { - // The private route itself + /// The private route itself private_route: Option, /// Did this remote private route see our node info due to no safety route in use last_seen_our_node_info_ts: Timestamp, @@ -256,13 +261,13 @@ pub struct RouteSpecStoreCache { /// Route spec hop cache, used to quickly disqualify routes hop_cache: HashSet>, /// Has a remote private route responded to a question and when - remote_private_route_cache: LruCache, + remote_private_route_cache: LruCache, /// Compiled route cache compiled_route_cache: LruCache, /// List of dead allocated routes - dead_routes: Vec, + dead_routes: Vec, /// List of dead remote routes - dead_remote_routes: Vec, + dead_remote_routes: Vec, } impl Default for RouteSpecStoreCache { @@ -602,6 +607,7 @@ impl RouteSpecStore { /// Prefers nodes that are not currently in use by another route /// The route is not yet tested for its reachability /// Returns None if no route could be allocated at this time + /// Returns Some list of public keys for the requested set of crypto kinds #[instrument(level = "trace", skip(self), ret, err)] pub fn allocate_route( &self, @@ -1590,8 +1596,8 @@ impl RouteSpecStore { rti: &RoutingTableInner, safety_spec: &SafetySpec, direction: DirectionSet, - avoid_nodes: &[TypedKey], - ) -> EyreResult> { + avoid_nodes: &[PublicKey], + ) -> EyreResult> { // Ensure the total hop count isn't too long for our config let max_route_hop_count = self.unlocked_inner.max_route_hop_count; if safety_spec.hop_count == 0 { @@ -1645,13 +1651,14 @@ impl RouteSpecStore { Ok(Some(sr_pubkey)) } - /// Get a private sroute to use for the answer to question + /// Get a private route to use for the answer to question #[instrument(level = "trace", skip(self), ret, err)] pub fn get_private_route_for_safety_spec( &self, + crypto_kind: CryptoKind, safety_spec: &SafetySpec, - avoid_nodes: &[TypedKey], - ) -> EyreResult> { + avoid_nodes: &[PublicKey], + ) -> EyreResult> { let inner = &mut *self.inner.lock(); let routing_table = self.unlocked_inner.routing_table.clone(); let rti = &*routing_table.inner.read(); @@ -1669,7 +1676,7 @@ impl RouteSpecStore { #[instrument(level = "trace", skip(self), err)] pub fn assemble_private_route( &self, - key: &TypedKey, + key: &PublicKey, optimized: Option, ) -> EyreResult { let inner = &*self.inner.lock(); @@ -1758,7 +1765,7 @@ impl RouteSpecStore { /// Import a remote private route for compilation #[instrument(level = "trace", skip(self, blob), ret, err)] - pub fn import_remote_private_route(&self, blob: Vec) -> EyreResult { + pub fn import_remote_private_route(&self, blob: Vec) -> EyreResult { // decode the pr blob let private_route = RouteSpecStore::blob_to_private_route(blob)?; @@ -1783,7 +1790,7 @@ impl RouteSpecStore { /// Release a remote private route that is no longer in use #[instrument(level = "trace", skip(self), ret)] - fn release_remote_private_route(&self, key: &TypedKey) -> bool { + fn release_remote_private_route(&self, key: &PublicKey) -> bool { let inner = &mut *self.inner.lock(); if inner.cache.remote_private_route_cache.remove(key).is_some() { // Mark it as dead for the update @@ -1795,7 +1802,7 @@ impl RouteSpecStore { } /// Retrieve an imported remote private route by its public key - pub fn get_remote_private_route(&self, key: &TypedKey) -> Option { + pub fn get_remote_private_route(&self, key: &PublicKey) -> Option { let inner = &mut *self.inner.lock(); let cur_ts = get_aligned_timestamp(); Self::with_get_remote_private_route(inner, cur_ts, key, |r| { @@ -1804,7 +1811,7 @@ impl RouteSpecStore { } /// Retrieve an imported remote private route by its public key but don't 'touch' it - pub fn peek_remote_private_route(&self, key: &TypedKey) -> Option { + pub fn peek_remote_private_route(&self, key: &PublicKey) -> Option { let inner = &mut *self.inner.lock(); let cur_ts = get_aligned_timestamp(); Self::with_peek_remote_private_route(inner, cur_ts, key, |r| { @@ -1865,7 +1872,7 @@ impl RouteSpecStore { fn with_get_remote_private_route( inner: &mut RouteSpecStoreInner, cur_ts: Timestamp, - remote_private_route: &TypedKey, + key: &PublicKey, f: F, ) -> Option where @@ -1885,7 +1892,7 @@ impl RouteSpecStore { fn with_peek_remote_private_route( inner: &mut RouteSpecStoreInner, cur_ts: Timestamp, - remote_private_route: &TypedKey, + key: &PublicKey, f: F, ) -> Option where @@ -1907,7 +1914,7 @@ impl RouteSpecStore { /// Check to see if this remote (not ours) private route has seen our current node info yet /// This happens when you communicate with a private route without a safety route - pub fn has_remote_private_route_seen_our_node_info(&self, remote_private_route: &TypedKey) -> bool { + pub fn has_remote_private_route_seen_our_node_info(&self, key: &PublicKey) -> bool { let our_node_info_ts = { let rti = &*self.unlocked_inner.routing_table.inner.read(); let Some(ts) = rti.get_own_node_info_ts(RoutingDomain::PublicInternet) else { @@ -1919,7 +1926,7 @@ impl RouteSpecStore { let opt_rpr_node_info_ts = { let inner = &mut *self.inner.lock(); let cur_ts = get_aligned_timestamp(); - Self::with_peek_remote_private_route(inner, cur_ts, remote_private_route, |rpr| { + Self::with_peek_remote_private_route(inner, cur_ts, key, |rpr| { rpr.last_seen_our_node_info_ts }) }; diff --git a/veilid-core/src/rpc_processor/coders/operations/operation.rs b/veilid-core/src/rpc_processor/coders/operations/operation.rs index 5c19adca..8f8790bd 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation.rs @@ -16,12 +16,15 @@ impl RPCOperationKind { } } - pub fn decode(kind_reader: &veilid_capnp::operation::kind::Reader) -> Result { + pub fn decode( + kind_reader: &veilid_capnp::operation::kind::Reader, + crypto: Crypto, + ) -> Result { let which_reader = kind_reader.which().map_err(RPCError::protocol)?; let out = match which_reader { veilid_capnp::operation::kind::Which::Question(r) => { let q_reader = r.map_err(RPCError::protocol)?; - let out = RPCQuestion::decode(&q_reader)?; + let out = RPCQuestion::decode(&q_reader, crypto)?; RPCOperationKind::Question(out) } veilid_capnp::operation::kind::Which::Statement(r) => { @@ -54,31 +57,25 @@ impl RPCOperationKind { #[derive(Debug, Clone)] pub struct RPCOperation { op_id: OperationId, - sender_node_info: Option, + opt_sender_peer_info: Option, target_node_info_ts: Timestamp, kind: RPCOperationKind, } impl RPCOperation { - pub fn new_question( - question: RPCQuestion, - sender_signed_node_info: SenderSignedNodeInfo, - ) -> Self { + pub fn new_question(question: RPCQuestion, sender_peer_info: SenderPeerInfo) -> Self { Self { op_id: OperationId::new(get_random_u64()), - sender_node_info: sender_signed_node_info.signed_node_info, - target_node_info_ts: sender_signed_node_info.target_node_info_ts, + opt_sender_peer_info: sender_peer_info.opt_sender_peer_info, + target_node_info_ts: sender_peer_info.target_node_info_ts, kind: RPCOperationKind::Question(question), } } - pub fn new_statement( - statement: RPCStatement, - sender_signed_node_info: SenderSignedNodeInfo, - ) -> Self { + pub fn new_statement(statement: RPCStatement, sender_peer_info: SenderPeerInfo) -> Self { Self { op_id: OperationId::new(get_random_u64()), - sender_node_info: sender_signed_node_info.signed_node_info, - target_node_info_ts: sender_signed_node_info.target_node_info_ts, + opt_sender_peer_info: sender_peer_info.opt_sender_peer_info, + target_node_info_ts: sender_peer_info.target_node_info_ts, kind: RPCOperationKind::Statement(statement), } } @@ -86,12 +83,12 @@ impl RPCOperation { pub fn new_answer( request: &RPCOperation, answer: RPCAnswer, - sender_signed_node_info: SenderSignedNodeInfo, + sender_peer_info: SenderPeerInfo, ) -> Self { Self { op_id: request.op_id, - sender_node_info: sender_signed_node_info.signed_node_info, - target_node_info_ts: sender_signed_node_info.target_node_info_ts, + opt_sender_peer_info: sender_peer_info.opt_sender_peer_info, + target_node_info_ts: sender_peer_info.target_node_info_ts, kind: RPCOperationKind::Answer(answer), } } @@ -100,8 +97,8 @@ impl RPCOperation { self.op_id } - pub fn sender_node_info(&self) -> Option<&SignedNodeInfo> { - self.sender_node_info.as_ref() + pub fn sender_peer_info(&self) -> Option<&PeerInfo> { + self.opt_sender_peer_info.as_ref() } pub fn target_node_info_ts(&self) -> Timestamp { self.target_node_info_ts @@ -117,20 +114,16 @@ impl RPCOperation { pub fn decode( operation_reader: &veilid_capnp::operation::Reader, - opt_sender_node_id: Option<&TypedKey>, + crypto: Crypto, ) -> Result { let op_id = OperationId::new(operation_reader.get_op_id()); - let sender_node_info = if operation_reader.has_sender_node_info() { - if let Some(sender_node_id) = opt_sender_node_id { - let sni_reader = operation_reader - .get_sender_node_info() - .map_err(RPCError::protocol)?; - let sni = decode_signed_node_info(&sni_reader, sender_node_id)?; - Some(sni) - } else { - None - } + let sender_peer_info = if operation_reader.has_sender_peer_info() { + let pi_reader = operation_reader + .get_sender_peer_info() + .map_err(RPCError::protocol)?; + let pi = decode_peer_info(&pi_reader, crypto.clone())?; + Some(pi) } else { None }; @@ -138,11 +131,11 @@ impl RPCOperation { let target_node_info_ts = Timestamp::new(operation_reader.get_target_node_info_ts()); let kind_reader = operation_reader.get_kind(); - let kind = RPCOperationKind::decode(&kind_reader)?; + let kind = RPCOperationKind::decode(&kind_reader, crypto)?; Ok(RPCOperation { op_id, - sender_node_info, + opt_sender_peer_info: sender_peer_info, target_node_info_ts, kind, }) @@ -150,9 +143,9 @@ impl RPCOperation { pub fn encode(&self, builder: &mut veilid_capnp::operation::Builder) -> Result<(), RPCError> { builder.set_op_id(self.op_id.as_u64()); - if let Some(sender_info) = &self.sender_node_info { - let mut si_builder = builder.reborrow().init_sender_node_info(); - encode_signed_node_info(&sender_info, &mut si_builder)?; + if let Some(sender_peer_info) = &self.opt_sender_peer_info { + let mut pi_builder = builder.reborrow().init_sender_peer_info(); + encode_peer_info(&sender_peer_info, &mut pi_builder)?; } builder.set_target_node_info_ts(self.target_node_info_ts.as_u64()); let mut k_builder = builder.reborrow().init_kind(); diff --git a/veilid-core/src/rpc_processor/coders/operations/question.rs b/veilid-core/src/rpc_processor/coders/operations/question.rs index 4e7e3966..e3f50776 100644 --- a/veilid-core/src/rpc_processor/coders/operations/question.rs +++ b/veilid-core/src/rpc_processor/coders/operations/question.rs @@ -19,9 +19,12 @@ impl RPCQuestion { pub fn desc(&self) -> &'static str { self.detail.desc() } - pub fn decode(reader: &veilid_capnp::question::Reader) -> Result { + pub fn decode( + reader: &veilid_capnp::question::Reader, + crypto: Crypto, + ) -> Result { let rt_reader = reader.get_respond_to(); - let respond_to = RespondTo::decode(&rt_reader)?; + let respond_to = RespondTo::decode(&rt_reader, crypto)?; let d_reader = reader.get_detail(); let detail = RPCQuestionDetail::decode(&d_reader)?; Ok(RPCQuestion { respond_to, detail }) diff --git a/veilid-core/src/rpc_processor/coders/operations/respond_to.rs b/veilid-core/src/rpc_processor/coders/operations/respond_to.rs index f05b6d08..43d6f871 100644 --- a/veilid-core/src/rpc_processor/coders/operations/respond_to.rs +++ b/veilid-core/src/rpc_processor/coders/operations/respond_to.rs @@ -23,12 +23,15 @@ impl RespondTo { Ok(()) } - pub fn decode(reader: &veilid_capnp::question::respond_to::Reader) -> Result { + pub fn decode( + reader: &veilid_capnp::question::respond_to::Reader, + crypto: Crypto, + ) -> Result { let respond_to = match reader.which().map_err(RPCError::protocol)? { veilid_capnp::question::respond_to::Sender(()) => RespondTo::Sender, veilid_capnp::question::respond_to::PrivateRoute(pr_reader) => { let pr_reader = pr_reader.map_err(RPCError::protocol)?; - let pr = decode_private_route(&pr_reader)?; + let pr = decode_private_route(&pr_reader, crypto)?; RespondTo::PrivateRoute(pr) } }; diff --git a/veilid-core/src/rpc_processor/coders/private_safety_route.rs b/veilid-core/src/rpc_processor/coders/private_safety_route.rs index 8baf2450..86d63d03 100644 --- a/veilid-core/src/rpc_processor/coders/private_safety_route.rs +++ b/veilid-core/src/rpc_processor/coders/private_safety_route.rs @@ -53,7 +53,7 @@ pub fn encode_route_hop( match &route_hop.node { RouteNode::NodeId(ni) => { let mut ni_builder = node_builder.init_node_id(); - encode_key256(&ni.key, &mut ni_builder)?; + encode_key256(&ni, &mut ni_builder); } RouteNode::PeerInfo(pi) => { let mut pi_builder = node_builder.init_peer_info(); @@ -67,17 +67,20 @@ pub fn encode_route_hop( Ok(()) } -pub fn decode_route_hop(reader: &veilid_capnp::route_hop::Reader) -> Result { +pub fn decode_route_hop( + reader: &veilid_capnp::route_hop::Reader, + crypto: Crypto, +) -> Result { let n_reader = reader.reborrow().get_node(); let node = match n_reader.which().map_err(RPCError::protocol)? { veilid_capnp::route_hop::node::Which::NodeId(ni) => { let ni_reader = ni.map_err(RPCError::protocol)?; - RouteNode::NodeId(NodeId::new(decode_key256(&ni_reader))) + RouteNode::NodeId(decode_key256(&ni_reader)) } veilid_capnp::route_hop::node::Which::PeerInfo(pi) => { let pi_reader = pi.map_err(RPCError::protocol)?; RouteNode::PeerInfo( - decode_peer_info(&pi_reader) + decode_peer_info(&pi_reader, crypto) .map_err(RPCError::map_protocol("invalid peer info in route hop"))?, ) } @@ -101,10 +104,10 @@ pub fn encode_private_route( private_route: &PrivateRoute, builder: &mut veilid_capnp::private_route::Builder, ) -> Result<(), RPCError> { - encode_key256( + encode_typed_key( &private_route.public_key, &mut builder.reborrow().init_public_key(), - )?; + ); builder.set_hop_count(private_route.hop_count); let mut h_builder = builder.reborrow().init_hops(); match &private_route.hops { @@ -125,16 +128,17 @@ pub fn encode_private_route( pub fn decode_private_route( reader: &veilid_capnp::private_route::Reader, + crypto: Crypto, ) -> Result { - let public_key = decode_key256(&reader.get_public_key().map_err(RPCError::map_protocol( - "invalid public key in private route", - ))?); + let public_key = decode_typed_key(&reader.get_public_key().map_err( + RPCError::map_protocol("invalid public key in private route"), + )?)?; let hop_count = reader.get_hop_count(); let hops = match reader.get_hops().which().map_err(RPCError::protocol)? { veilid_capnp::private_route::hops::Which::FirstHop(rh_reader) => { let rh_reader = rh_reader.map_err(RPCError::protocol)?; - PrivateRouteHops::FirstHop(decode_route_hop(&rh_reader)?) + PrivateRouteHops::FirstHop(decode_route_hop(&rh_reader, crypto)?) } veilid_capnp::private_route::hops::Which::Data(rhd_reader) => { let rhd_reader = rhd_reader.map_err(RPCError::protocol)?; @@ -156,10 +160,10 @@ pub fn encode_safety_route( safety_route: &SafetyRoute, builder: &mut veilid_capnp::safety_route::Builder, ) -> Result<(), RPCError> { - encode_key256( + encode_typed_key( &safety_route.public_key, &mut builder.reborrow().init_public_key(), - )?; + ); builder.set_hop_count(safety_route.hop_count); let h_builder = builder.reborrow().init_hops(); match &safety_route.hops { @@ -178,12 +182,13 @@ pub fn encode_safety_route( pub fn decode_safety_route( reader: &veilid_capnp::safety_route::Reader, + crypto: Crypto, ) -> Result { - let public_key = decode_key256( + let public_key = decode_typed_key( &reader .get_public_key() .map_err(RPCError::map_protocol("invalid public key in safety route"))?, - ); + )?; let hop_count = reader.get_hop_count(); let hops = match reader.get_hops().which().map_err(RPCError::protocol)? { veilid_capnp::safety_route::hops::Which::Data(rhd_reader) => { @@ -192,7 +197,7 @@ pub fn decode_safety_route( } veilid_capnp::safety_route::hops::Which::Private(pr_reader) => { let pr_reader = pr_reader.map_err(RPCError::protocol)?; - SafetyRouteHops::Private(decode_private_route(&pr_reader)?) + SafetyRouteHops::Private(decode_private_route(&pr_reader, crypto)?) } }; diff --git a/veilid-core/src/rpc_processor/destination.rs b/veilid-core/src/rpc_processor/destination.rs index c33e3592..9161de40 100644 --- a/veilid-core/src/rpc_processor/destination.rs +++ b/veilid-core/src/rpc_processor/destination.rs @@ -162,8 +162,9 @@ impl RPCProcessor { } SafetySelection::Safe(safety_spec) => { // Sent directly but with a safety route, respond to private route + let ck = target.best_node_id().kind; let Some(pr_key) = rss - .get_private_route_for_safety_spec(safety_spec, &target.node_ids()) + .get_private_route_for_safety_spec(ck, safety_spec, &target.node_ids().keys()) .map_err(RPCError::internal)? else { return Ok(NetworkResult::no_connection_other("no private route for response at this time")); }; @@ -187,10 +188,12 @@ impl RPCProcessor { } SafetySelection::Safe(safety_spec) => { // Sent via a relay but with a safety route, respond to private route + let ck = target.best_node_id().kind; + let mut avoid_nodes = relay.node_ids(); avoid_nodes.add_all(&target.node_ids()); let Some(pr_key) = rss - .get_private_route_for_safety_spec(safety_spec, &avoid_nodes) + .get_private_route_for_safety_spec(ck, safety_spec, &avoid_nodes.keys()) .map_err(RPCError::internal)? else { return Ok(NetworkResult::no_connection_other("no private route for response at this time")); }; @@ -219,13 +222,13 @@ impl RPCProcessor { // Determine if we can use optimized nodeinfo let route_node = match rss - .has_remote_private_route_seen_our_node_info(&private_route.public_key) + .has_remote_private_route_seen_our_node_info(&private_route.public_key.key) { true => { if !routing_table.has_valid_own_node_info(RoutingDomain::PublicInternet) { return Ok(NetworkResult::no_connection_other("Own node info must be valid to use private route")); } - RouteNode::NodeId(routing_table.node_id(crypto_kind)) + RouteNode::NodeId(routing_table.node_id(crypto_kind).key) } false => { let Some(own_peer_info) = @@ -245,14 +248,14 @@ impl RPCProcessor { // Check for loopback test let pr_key = if safety_spec.preferred_route - == Some(private_route.public_key) + == Some(private_route.public_key.key) { // Private route is also safety route during loopback test - private_route.public_key + private_route.public_key.key } else { - // Get the privat route to respond to that matches the safety route spec we sent the request with + // Get the private route to respond to that matches the safety route spec we sent the request with let Some(pr_key) = rss - .get_private_route_for_safety_spec(safety_spec, &[avoid_node_id]) + .get_private_route_for_safety_spec(crypto_kind, safety_spec, &[avoid_node_id]) .map_err(RPCError::internal)? else { return Ok(NetworkResult::no_connection_other("no private route for response at this time")); }; @@ -300,18 +303,25 @@ impl RPCProcessor { }; // Reply directly to the request's source - let sender_id = TypedKey::new(detail.envelope.get_crypto_kind(), detail.envelope.get_sender_id(); + let sender_node_id = TypedKey::new(detail.envelope.get_crypto_kind(), detail.envelope.get_sender_id()); // This may be a different node's reference than the 'sender' in the case of a relay let peer_noderef = detail.peer_noderef.clone(); // If the sender_id is that of the peer, then this is a direct reply // else it is a relayed reply through the peer - xxx continue here, make sure respond to semantics are correct - if peer_noderef.node_id() == sender_id { + if peer_noderef.node_ids().contains(&sender_node_id) { NetworkResult::value(Destination::direct(peer_noderef)) } else { - NetworkResult::value(Destination::relay(peer_noderef, sender_id)) + // Look up the sender node, we should have added it via senderNodeInfo before getting here. + if let Some(sender_noderef) = self.routing_table.lookup_node_ref(sender_node_id) { + NetworkResult::value(Destination::relay(peer_noderef, sender_noderef)) + } else { + return NetworkResult::invalid_message( + "not responding to sender that has no node info", + ); + } + } } RespondTo::PrivateRoute(pr) => { diff --git a/veilid-core/src/rpc_processor/mod.rs b/veilid-core/src/rpc_processor/mod.rs index 64b91ecc..7f625d8a 100644 --- a/veilid-core/src/rpc_processor/mod.rs +++ b/veilid-core/src/rpc_processor/mod.rs @@ -179,22 +179,22 @@ struct RenderedOperation { /// Node information exchanged during every RPC message #[derive(Default, Debug, Clone)] -pub struct SenderSignedNodeInfo { - /// The current signed node info of the sender if required - signed_node_info: Option, +pub struct SenderPeerInfo { + /// The current peer info of the sender if required + opt_sender_peer_info: Option, /// The last timestamp of the target's node info to assist remote node with sending its latest node info target_node_info_ts: Timestamp, } -impl SenderSignedNodeInfo { - pub fn new_no_sni(target_node_info_ts: Timestamp) -> Self { +impl SenderPeerInfo { + pub fn new_no_peer_info(target_node_info_ts: Timestamp) -> Self { Self { - signed_node_info: None, + opt_sender_peer_info: None, target_node_info_ts, } } - pub fn new(sender_signed_node_info: SignedNodeInfo, target_node_info_ts: Timestamp) -> Self { + pub fn new(sender_peer_info: PeerInfo, target_node_info_ts: Timestamp) -> Self { Self { - signed_node_info: Some(sender_signed_node_info), + opt_sender_peer_info: Some(sender_peer_info), target_node_info_ts, } } @@ -686,17 +686,14 @@ impl RPCProcessor { /// Get signed node info to package with RPC messages to improve /// routing table caching when it is okay to do so #[instrument(level = "trace", skip(self), ret, err)] - fn get_sender_signed_node_info( - &self, - dest: &Destination, - ) -> Result { + fn get_sender_signed_node_info(&self, dest: &Destination) -> Result { // Don't do this if the sender is to remain private // Otherwise we would be attaching the original sender's identity to the final destination, // thus defeating the purpose of the safety route entirely :P match dest.get_safety_selection() { SafetySelection::Unsafe(_) => {} SafetySelection::Safe(_) => { - return Ok(SenderSignedNodeInfo::default()); + return Ok(SenderPeerInfo::default()); } } @@ -716,14 +713,14 @@ impl RPCProcessor { target } else { // Target was not in our routing table - return Ok(SenderSignedNodeInfo::default()); + return Ok(SenderPeerInfo::default()); } } Destination::PrivateRoute { private_route: _, safety_selection: _, } => { - return Ok(SenderSignedNodeInfo::default()); + return Ok(SenderPeerInfo::default()); } }; @@ -737,7 +734,7 @@ impl RPCProcessor { // Don't return our node info if it's not valid yet let Some(own_peer_info) = routing_table.get_own_peer_info(routing_domain) else { - return Ok(SenderSignedNodeInfo::new_no_sni(target_node_info_ts)); + return Ok(SenderPeerInfo::new_no_peer_info(target_node_info_ts)); }; // Get our node info timestamp @@ -745,10 +742,10 @@ impl RPCProcessor { // If the target has seen our node info already don't send it again if target.has_seen_our_node_info_ts(routing_domain, our_node_info_ts) { - return Ok(SenderSignedNodeInfo::new_no_sni(target_node_info_ts)); + return Ok(SenderPeerInfo::new_no_peer_info(target_node_info_ts)); } - Ok(SenderSignedNodeInfo::new( + Ok(SenderPeerInfo::new( own_peer_info.signed_node_info, target_node_info_ts, )) @@ -1205,19 +1202,20 @@ impl RPCProcessor { RPCOperation::decode(&op_reader, Some(&sender_node_id))? }; - // Get the sender noderef, incorporating and 'sender node info' + // Get the sender noderef, incorporating sender's peer info let mut opt_sender_nr: Option = None; - if let Some(sender_node_info) = operation.sender_node_info() { - // Sender NodeInfo was specified, update our routing table with it - if !self.filter_node_info(routing_domain, &sender_node_info) { + if let Some(sender_peer_info) = operation.sender_peer_info() { + // Ensure the sender peer info is for the actual sender specified in the envelope + + // Sender PeerInfo was specified, update our routing table with it + if !self.filter_node_info(routing_domain, &sender_peer_info) { return Err(RPCError::invalid_format( - "sender signednodeinfo has invalid peer scope", + "sender peerinfo has invalid peer scope", )); } - opt_sender_nr = self.routing_table().register_node_with_signed_node_info( + opt_sender_nr = self.routing_table().register_node_with_peer_info( routing_domain, - sender_node_id, - sender_node_info.clone(), + sender_peer_info, false, ); } diff --git a/veilid-core/src/veilid_api/api.rs b/veilid-core/src/veilid_api/api.rs index a6f1cd96..0231349e 100644 --- a/veilid-core/src/veilid_api/api.rs +++ b/veilid-core/src/veilid_api/api.rs @@ -116,7 +116,7 @@ impl VeilidAPI { //////////////////////////////////////////////////////////////// // Attach/Detach - // get a full copy of the current state + /// Get a full copy of the current state pub async fn get_state(&self) -> Result { let attachment_manager = self.attachment_manager()?; let network_manager = attachment_manager.network_manager(); @@ -133,9 +133,7 @@ impl VeilidAPI { }) } - // get network connectedness - - // connect to the network + /// Connect to the network #[instrument(level = "debug", err, skip_all)] pub async fn attach(&self) -> Result<(), VeilidAPIError> { let attachment_manager = self.attachment_manager()?; @@ -145,7 +143,7 @@ impl VeilidAPI { Ok(()) } - // disconnect from the network + /// Disconnect from the network #[instrument(level = "debug", err, skip_all)] pub async fn detach(&self) -> Result<(), VeilidAPIError> { let attachment_manager = self.attachment_manager()?; @@ -166,8 +164,12 @@ impl VeilidAPI { //////////////////////////////////////////////////////////////// // Private route allocation + /// Allocate a new private route set with default cryptography and network options + /// Returns a list of the public key and published 'blob' pairs. Publishing as many of these + /// pairs as possible to the network is desirable as support for multiple cryptography + /// systems will require choosing a compatible route #[instrument(level = "debug", skip(self))] - pub async fn new_private_route(&self) -> Result<(TypedKeySet, Vec), VeilidAPIError> { + pub async fn new_private_route(&self) -> Result)>, VeilidAPIError> { self.new_custom_private_route( &VALID_CRYPTO_KINDS, Stability::default(), @@ -176,13 +178,14 @@ impl VeilidAPI { .await } + /// #[instrument(level = "debug", skip(self))] pub async fn new_custom_private_route( &self, crypto_kinds: &[CryptoKind], stability: Stability, sequencing: Sequencing, - ) -> Result<(TypedKeySet, Vec), VeilidAPIError> { + ) -> Result)>, VeilidAPIError> { let default_route_hop_count: usize = { let config = self.config()?; let c = config.get(); @@ -229,14 +232,14 @@ impl VeilidAPI { } #[instrument(level = "debug", skip(self))] - pub fn import_remote_private_route(&self, blob: Vec) -> Result { + pub fn import_remote_private_route(&self, blob: Vec) -> Result { let rss = self.routing_table()?.route_spec_store(); rss.import_remote_private_route(blob) .map_err(|e| VeilidAPIError::invalid_argument(e, "blob", "private route blob")) } #[instrument(level = "debug", skip(self))] - pub fn release_private_route(&self, key: &TypedKey) -> Result<(), VeilidAPIError> { + pub fn release_private_route(&self, key: &PublicKey) -> Result<(), VeilidAPIError> { let rss = self.routing_table()?.route_spec_store(); if rss.release_route(key) { Ok(()) diff --git a/veilid-core/src/veilid_api/error.rs b/veilid-core/src/veilid_api/error.rs index e2411841..5da01f9e 100644 --- a/veilid-core/src/veilid_api/error.rs +++ b/veilid-core/src/veilid_api/error.rs @@ -147,7 +147,7 @@ impl VeilidAPIError { pub fn shutdown() -> Self { Self::Shutdown } - pub fn key_not_found(key: TypedKey) -> Self { + pub fn key_not_found(key: PublicKey) -> Self { Self::KeyNotFound { key } } pub fn no_connection(msg: T) -> Self { diff --git a/veilid-core/src/veilid_api/routing_context.rs b/veilid-core/src/veilid_api/routing_context.rs index 3b5ec2f3..2fcf43be 100644 --- a/veilid-core/src/veilid_api/routing_context.rs +++ b/veilid-core/src/veilid_api/routing_context.rs @@ -4,8 +4,8 @@ use super::*; #[derive(Clone, Debug)] pub enum Target { - NodeId(TypedKey), - PrivateRoute(TypedKey), + NodeId(PublicKey), + PrivateRoute(PublicKey), } pub struct RoutingContextInner {} @@ -225,11 +225,11 @@ impl RoutingContext { /////////////////////////////////// /// Block Store - pub async fn find_block(&self, _block_id: TypedKey) -> Result, VeilidAPIError> { + pub async fn find_block(&self, _block_id: PublicKey) -> Result, VeilidAPIError> { panic!("unimplemented"); } - pub async fn supply_block(&self, _block_id: TypedKey) -> Result { + pub async fn supply_block(&self, _block_id: PublicKey) -> Result { panic!("unimplemented"); } } diff --git a/veilid-core/src/veilid_api/types.rs b/veilid-core/src/veilid_api/types.rs index 5e79231c..0614c2ba 100644 --- a/veilid-core/src/veilid_api/types.rs +++ b/veilid-core/src/veilid_api/types.rs @@ -159,7 +159,7 @@ pub struct VeilidLog { pub struct VeilidAppMessage { /// Some(sender) if the message was sent directly, None if received via a private/safety route #[serde(with = "opt_json_as_string")] - pub sender: Option, + pub sender: Option, /// The content of the message to deliver to the application #[serde(with = "json_as_base64")] pub message: Vec, @@ -173,7 +173,7 @@ pub struct VeilidAppMessage { pub struct VeilidAppCall { /// Some(sender) if the request was sent directly, None if received via a private/safety route #[serde(with = "opt_json_as_string")] - pub sender: Option, + pub sender: Option, /// The content of the request to deliver to the application #[serde(with = "json_as_base64")] pub message: Vec, @@ -513,7 +513,7 @@ impl SafetySelection { #[archive_attr(repr(C), derive(CheckBytes))] pub struct SafetySpec { /// preferred safety route if it still exists - pub preferred_route: Option, + pub preferred_route: Option, /// must be greater than 0 pub hop_count: usize, /// prefer reliability over speed