checkpoint

This commit is contained in:
John Smith
2022-11-22 18:26:39 -05:00
parent 27f7f49d4f
commit dec7bd27da
7 changed files with 280 additions and 88 deletions

View File

@@ -7,7 +7,7 @@ use routing_table::*;
#[derive(Default, Debug)]
struct DebugCache {
imported_routes: Vec<PrivateRoute>,
imported_routes: Vec<DHTKey>,
}
static DEBUG_CACHE: Mutex<DebugCache> = Mutex::new(DebugCache {
@@ -123,10 +123,20 @@ fn get_destination(routing_table: RoutingTable) -> impl FnOnce(&str) -> Option<D
// Private route
let text = &text[1..];
let n = get_number(text)?;
let dc = DEBUG_CACHE.lock();
let r = dc.imported_routes.get(n)?;
let mut dc = DEBUG_CACHE.lock();
let pr_pubkey = dc.imported_routes.get(n)?;
let rss = routing_table.route_spec_store();
let private_route = match rss.get_remote_private_route(&pr_pubkey) {
Err(_) => {
// Remove imported route
dc.imported_routes.remove(n);
info!("removed dead imported route {}", n);
return None;
}
Ok(v) => v,
};
Some(Destination::private_route(
r.clone(),
private_route,
ss.unwrap_or(SafetySelection::Unsafe(Sequencing::NoPreference)),
))
} else {
@@ -734,17 +744,24 @@ impl VeilidAPI {
let blob_dec = BASE64URL_NOPAD
.decode(blob.as_bytes())
.map_err(VeilidAPIError::generic)?;
let pr =
RouteSpecStore::blob_to_private_route(blob_dec).map_err(VeilidAPIError::generic)?;
let rss = self.routing_table()?.route_spec_store();
let pr_pubkey = rss
.import_remote_private_route(blob_dec)
.map_err(VeilidAPIError::generic)?;
let mut dc = DEBUG_CACHE.lock();
let n = dc.imported_routes.len();
let out = format!("Private route #{} imported: {}", n, pr.public_key);
dc.imported_routes.push(pr);
let out = format!("Private route #{} imported: {}", n, pr_pubkey);
dc.imported_routes.push(pr_pubkey);
return Ok(out);
}
async fn debug_route_test(&self, _args: Vec<String>) -> Result<String, VeilidAPIError> {
let out = "xxx".to_string();
return Ok(out);
}
async fn debug_route(&self, args: String) -> Result<String, VeilidAPIError> {
let args: Vec<String> = args.split_whitespace().map(|s| s.to_owned()).collect();
@@ -764,6 +781,8 @@ impl VeilidAPI {
self.debug_route_list(args).await
} else if command == "import" {
self.debug_route_import(args).await
} else if command == "test" {
self.debug_route_test(args).await
} else {
Ok(">>> Unknown command\n".to_owned())
}
@@ -791,6 +810,7 @@ impl VeilidAPI {
print <route>
list
import <blob>
test <route>
<destination> is:
* direct: <node>[+<safety>][<modifiers>]

View File

@@ -1,12 +1,10 @@
#![allow(dead_code)]
mod debug;
mod privacy;
mod routing_context;
mod serialize_helpers;
pub use debug::*;
pub use privacy::*;
pub use routing_context::*;
pub use serialize_helpers::*;
@@ -25,12 +23,13 @@ pub use intf::BlockStore;
pub use intf::ProtectedStore;
pub use intf::TableStore;
pub use network_manager::NetworkManager;
pub use routing_table::{NodeRef, NodeRefBase, RoutingTable};
pub use routing_table::{NodeRef, NodeRefBase};
use core::fmt;
use core_context::{api_shutdown, VeilidCoreContext};
use enumset::*;
use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
use routing_table::{RouteSpecStore, RoutingTable};
use rpc_processor::*;
use serde::*;
use xx::*;
@@ -86,8 +85,8 @@ pub enum VeilidAPIError {
Timeout,
#[error("Shutdown")]
Shutdown,
#[error("Node not found: {node_id}")]
NodeNotFound { node_id: NodeId },
#[error("Key not found: {key}")]
KeyNotFound { key: DHTKey },
#[error("No connection: {message}")]
NoConnection { message: String },
#[error("No peer info: {node_id}")]
@@ -123,11 +122,13 @@ impl VeilidAPIError {
pub fn shutdown() -> Self {
Self::Shutdown
}
pub fn node_not_found(node_id: NodeId) -> Self {
Self::NodeNotFound { node_id }
pub fn key_not_found(key: DHTKey) -> Self {
Self::KeyNotFound { key }
}
pub fn no_connection(message: String) -> Self {
Self::NoConnection { message }
pub fn no_connection<T: ToString>(msg: T) -> Self {
Self::NoConnection {
message: msg.to_string(),
}
}
pub fn no_peer_info(node_id: NodeId) -> Self {
Self::NoPeerInfo { node_id }
@@ -2681,6 +2682,13 @@ impl VeilidAPI {
}
Err(VeilidAPIError::NotInitialized)
}
pub fn routing_table(&self) -> Result<RoutingTable, VeilidAPIError> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
return Ok(context.attachment_manager.network_manager().routing_table());
}
Err(VeilidAPIError::NotInitialized)
}
////////////////////////////////////////////////////////////////
// Attach/Detach
@@ -2732,6 +2740,64 @@ impl VeilidAPI {
RoutingContext::new(self.clone())
}
////////////////////////////////////////////////////////////////
// Private route allocation
#[instrument(level = "debug", skip(self))]
pub async fn new_default_private_route(&self) -> Result<(DHTKey, Vec<u8>), VeilidAPIError> {
let config = self.config()?;
let c = config.get();
self.new_private_route(
Stability::LowLatency,
Sequencing::NoPreference,
c.network.rpc.default_route_hop_count.into(),
)
.await
}
#[instrument(level = "debug", skip(self))]
pub async fn new_private_route(
&self,
stability: Stability,
sequencing: Sequencing,
hop_count: usize,
) -> Result<(DHTKey, Vec<u8>), VeilidAPIError> {
let rss = self.routing_table()?.route_spec_store();
let r = rss
.allocate_route(
stability,
sequencing,
hop_count,
Direction::Inbound.into(),
&[],
)
.map_err(VeilidAPIError::internal)?;
let Some(pr_pubkey) = r else {
return Err(VeilidAPIError::generic("unable to allocate route"));
};
if !rss
.test_route(&pr_pubkey)
.await
.map_err(VeilidAPIError::no_connection)?
{
rss.release_route(pr_pubkey)
.map_err(VeilidAPIError::generic)?;
return Err(VeilidAPIError::generic("allocated route failed to test"));
}
let private_route = rss
.assemble_private_route(&pr_pubkey, Some(true))
.map_err(VeilidAPIError::generic)?;
let blob = match RouteSpecStore::private_route_to_blob(&private_route) {
Ok(v) => v,
Err(e) => {
rss.release_route(pr_pubkey)
.map_err(VeilidAPIError::generic)?;
return Err(VeilidAPIError::internal(e));
}
};
Ok((pr_pubkey, blob))
}
////////////////////////////////////////////////////////////////
// App Calls

View File

@@ -1,174 +0,0 @@
use super::*;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Compiled Privacy Objects
/// An encrypted private/safety route hop
#[derive(Clone, Debug)]
pub struct RouteHopData {
/// The nonce used in the encryption ENC(Xn,DH(PKn,SKapr))
pub nonce: Nonce,
/// The encrypted blob
pub blob: Vec<u8>,
}
/// How to find a route node
#[derive(Clone, Debug)]
pub enum RouteNode {
/// Route node is optimized, no contact method information as this node id has been seen before
NodeId(NodeId),
/// Route node with full contact method information to ensure the peer is reachable
PeerInfo(PeerInfo),
}
impl fmt::Display for RouteNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
RouteNode::NodeId(x) => x.key.encode(),
RouteNode::PeerInfo(pi) => pi.node_id.key.encode(),
}
)
}
}
/// An unencrypted private/safety route hop
#[derive(Clone, Debug)]
pub struct RouteHop {
/// The location of the hop
pub node: RouteNode,
/// The encrypted blob to pass to the next hop as its data (None for stubs)
pub next_hop: Option<RouteHopData>,
}
/// The kind of hops a private route can have
#[derive(Clone, Debug)]
pub enum PrivateRouteHops {
/// The first hop of a private route, unencrypted, route_hops == total hop count
FirstHop(RouteHop),
/// Private route internal node. Has > 0 private route hops left but < total hop count
Data(RouteHopData),
/// Private route has ended (hop count = 0)
Empty,
}
/// A private route for receiver privacy
#[derive(Clone, Debug)]
pub struct PrivateRoute {
/// The public key used for the entire route
pub public_key: DHTKey,
pub hop_count: u8,
pub hops: PrivateRouteHops,
}
impl PrivateRoute {
/// Empty private route is the form used when receiving the last hop
pub fn new_empty(public_key: DHTKey) -> Self {
Self {
public_key,
hop_count: 0,
hops: PrivateRouteHops::Empty,
}
}
/// Stub route is the form used when no privacy is required, but you need to specify the destination for a safety route
pub fn new_stub(public_key: DHTKey, node: RouteNode) -> Self {
Self {
public_key,
hop_count: 1,
hops: PrivateRouteHops::FirstHop(RouteHop {
node,
next_hop: None,
}),
}
}
/// Remove the first unencrypted hop if possible
pub fn pop_first_hop(&mut self) -> Option<RouteNode> {
match &mut self.hops {
PrivateRouteHops::FirstHop(first_hop) => {
let first_hop_node = first_hop.node.clone();
// Reduce hop count
if self.hop_count > 0 {
self.hop_count -= 1;
} else {
error!("hop count should not be 0 for first hop");
}
// Go to next hop
self.hops = match first_hop.next_hop.take() {
Some(rhd) => PrivateRouteHops::Data(rhd),
None => PrivateRouteHops::Empty,
};
return Some(first_hop_node);
}
PrivateRouteHops::Data(_) => return None,
PrivateRouteHops::Empty => return None,
}
}
}
impl fmt::Display for PrivateRoute {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"PR({:?}+{}{})",
self.public_key,
self.hop_count,
match &self.hops {
PrivateRouteHops::FirstHop(fh) => {
format!("->{}", fh.node)
}
PrivateRouteHops::Data(_) => {
"->?".to_owned()
}
PrivateRouteHops::Empty => {
"".to_owned()
}
}
)
}
}
#[derive(Clone, Debug)]
pub enum SafetyRouteHops {
/// Has >= 1 safety route hops
Data(RouteHopData),
/// Has 0 safety route hops
Private(PrivateRoute),
}
#[derive(Clone, Debug)]
pub struct SafetyRoute {
pub public_key: DHTKey,
pub hop_count: u8,
pub hops: SafetyRouteHops,
}
impl SafetyRoute {
pub fn new_stub(public_key: DHTKey, private_route: PrivateRoute) -> Self {
assert!(matches!(private_route.hops, PrivateRouteHops::Data(_)));
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!(
f,
"SR({:?}+{}{})",
self.public_key,
self.hop_count,
match &self.hops {
SafetyRouteHops::Data(_) => "".to_owned(),
SafetyRouteHops::Private(p) => format!("->{}", p),
}
)
}
}

View File

@@ -4,7 +4,7 @@ use super::*;
#[derive(Clone, Debug)]
pub enum Target {
NodeId(NodeId),
PrivateRoute(PrivateRoute),
PrivateRoute(DHTKey),
}
pub struct RoutingContextInner {}
@@ -115,7 +115,7 @@ impl RoutingContext {
// Resolve node
let mut nr = match rpc_processor.resolve_node(node_id.key).await {
Ok(Some(nr)) => nr,
Ok(None) => return Err(VeilidAPIError::NodeNotFound { node_id }),
Ok(None) => return Err(VeilidAPIError::KeyNotFound { key: node_id.key }),
Err(e) => return Err(e.into()),
};
// Apply sequencing to match safety selection
@@ -126,10 +126,17 @@ impl RoutingContext {
safety_selection: self.unlocked_inner.safety_selection,
})
}
Target::PrivateRoute(pr) => Ok(rpc_processor::Destination::PrivateRoute {
private_route: pr,
safety_selection: self.unlocked_inner.safety_selection,
}),
Target::PrivateRoute(pr) => {
// Get remote private route
let rss = self.api.routing_table()?.route_spec_store();
let private_route = rss
.get_remote_private_route(&pr)
.map_err(|_| VeilidAPIError::KeyNotFound { key: pr })?;
Ok(rpc_processor::Destination::PrivateRoute {
private_route,
safety_selection: self.unlocked_inner.safety_selection,
})
}
}
}