checkpoint

This commit is contained in:
John Smith 2023-02-22 21:47:00 -05:00
parent 4085af7fc4
commit 8fc38febca
11 changed files with 216 additions and 110 deletions

View File

@ -201,8 +201,18 @@ impl TypedKeySet {
self.remove(*k); self.remove(*k);
} }
} }
/// Return preferred typed key of our supported crypto kinds
pub fn best(&self) -> Option<TypedKey> { pub fn best(&self) -> Option<TypedKey> {
self.items.first().copied() match self.items.first().copied() {
None => None,
Some(k) => {
if !VALID_CRYPTO_KINDS.contains(&k.kind) {
None
} else {
Some(k)
}
}
}
} }
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.items.len() self.items.len()
@ -221,6 +231,14 @@ impl TypedKeySet {
} }
false false
} }
pub fn contains_key(&self, key: &PublicKey) -> bool {
for tk in &self.items {
if tk.key == *key {
return true;
}
}
false
}
} }
impl core::ops::Deref for TypedKeySet { impl core::ops::Deref for TypedKeySet {
@ -264,6 +282,13 @@ impl FromStr for TypedKeySet {
Ok(Self { items }) Ok(Self { items })
} }
} }
impl From<TypedKey> for TypedKeySet {
fn from(x: TypedKey) -> Self {
let mut tks = TypedKeySet::with_capacity(1);
tks.add(x);
tks
}
}
#[derive( #[derive(
Clone, Clone,

View File

@ -145,6 +145,15 @@ impl RoutingTableUnlockedInner {
false false
} }
pub fn matches_own_node_id_key(&self, node_id_key: &PublicKey) -> bool {
for (ck, v) in &self.node_id_keypairs {
if v.key == *node_id_key {
return true;
}
}
false
}
pub fn calculate_bucket_index(&self, node_id: &TypedKey) -> (CryptoKind, usize) { pub fn calculate_bucket_index(&self, node_id: &TypedKey) -> (CryptoKind, usize) {
let crypto = self.crypto(); let crypto = self.crypto();
let self_node_id = self.node_id_keypairs.get(&node_id.kind).unwrap().key; let self_node_id = self.node_id_keypairs.get(&node_id.kind).unwrap().key;
@ -587,6 +596,13 @@ impl RoutingTable {
} }
} }
/// Resolve an existing routing table entry using any crypto kind and return a reference to it
pub fn lookup_any_node_ref(&self, node_id_key: PublicKey) -> Option<NodeRef> {
self.inner
.read()
.lookup_any_node_ref(self.clone(), node_id_key)
}
/// Resolve an existing routing table entry and return a reference to it /// Resolve an existing routing table entry and return a reference to it
pub fn lookup_node_ref(&self, node_id: TypedKey) -> Option<NodeRef> { pub fn lookup_node_ref(&self, node_id: TypedKey) -> Option<NodeRef> {
self.inner.read().lookup_node_ref(self.clone(), node_id) self.inner.read().lookup_node_ref(self.clone(), node_id)

View File

@ -1780,7 +1780,7 @@ impl RouteSpecStore {
/// Import a remote private route for compilation /// Import a remote private route for compilation
#[instrument(level = "trace", skip(self, blob), ret, err)] #[instrument(level = "trace", skip(self, blob), ret, err)]
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> EyreResult<TypedKeySet> { pub fn import_remote_private_route(&self, blob: Vec<u8>) -> EyreResult<TypedKeySet> { xxx continue here, maybe formalize 'private route set' as having its own non-key identifier for both remote and local routes... just a uuid map to typedkeyset?
// decode the pr blob // decode the pr blob
let private_routes = RouteSpecStore::blob_to_private_routes(blob)?; let private_routes = RouteSpecStore::blob_to_private_routes(blob)?;
@ -2006,7 +2006,7 @@ impl RouteSpecStore {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
// Check for stub route // Check for stub route
if *key == self.unlocked_inner.routing_table.node_id() { if self.unlocked_inner.routing_table.matches_own_node_id_key(key) {
return None; return None;
} }
// Check for local route // Check for local route
@ -2096,7 +2096,7 @@ impl RouteSpecStore {
} }
/// Convert binary blob to private route /// Convert binary blob to private route
pub fn blob_to_private_routes(blob: Vec<u8>) -> EyreResult<Vec<PrivateRoute>> { pub fn blob_to_private_routes(crypto: Crypto, blob: Vec<u8>) -> EyreResult<Vec<PrivateRoute>> {
// Deserialize count // Deserialize count
if blob.is_empty() { if blob.is_empty() {
@ -2123,7 +2123,7 @@ impl RouteSpecStore {
.get_root::<veilid_capnp::private_route::Reader>() .get_root::<veilid_capnp::private_route::Reader>()
.map_err(RPCError::internal) .map_err(RPCError::internal)
.wrap_err("failed to make reader for private_route")?; .wrap_err("failed to make reader for private_route")?;
let private_route = decode_private_route(&pr_reader).wrap_err("failed to decode private route")?; let private_route = decode_private_route(&pr_reader, crypto).wrap_err("failed to decode private route")?;
out.push(private_route); out.push(private_route);
} }
Ok(out) Ok(out)

View File

@ -678,6 +678,17 @@ impl RoutingTableInner {
Some(nr) Some(nr)
} }
/// Resolve an existing routing table entry using any crypto kind and return a reference to it
pub fn lookup_any_node_ref(
&self,
outer_self: RoutingTable,
node_id_key: PublicKey,
) -> Option<NodeRef> {
VALID_CRYPTO_KINDS
.iter()
.find_map(|ck| self.lookup_node_ref(outer_self, TypedKey::new(*ck, node_id_key)))
}
/// Resolve an existing routing table entry and return a reference to it /// Resolve an existing routing table entry and return a reference to it
pub fn lookup_node_ref(&self, outer_self: RoutingTable, node_id: TypedKey) -> Option<NodeRef> { pub fn lookup_node_ref(&self, outer_self: RoutingTable, node_id: TypedKey) -> Option<NodeRef> {
if self.unlocked_inner.matches_own_node_id(&[node_id]) { if self.unlocked_inner.matches_own_node_id(&[node_id]) {

View File

@ -92,7 +92,7 @@ impl RPCMessageHeader {
pub fn crypto_kind(&self) -> CryptoKind { pub fn crypto_kind(&self) -> CryptoKind {
match &self.detail { match &self.detail {
RPCMessageHeaderDetail::Direct(d) => d.envelope.get_crypto_kind(), RPCMessageHeaderDetail::Direct(d) => d.envelope.get_crypto_kind(),
RPCMessageHeaderDetail::SafetyRouted(s) => todo!(), RPCMessageHeaderDetail::SafetyRouted(s) => s.remote_safety_route.,
RPCMessageHeaderDetail::PrivateRouted(p) => todo!(), RPCMessageHeaderDetail::PrivateRouted(p) => todo!(),
} }
} }
@ -1199,7 +1199,7 @@ impl RPCProcessor {
let routing_domain = detail.routing_domain; let routing_domain = detail.routing_domain;
// Decode the operation // Decode the operation
let sender_node_id = detail.envelope.get_sender_id(); let sender_node_id = TypedKey::new(detail.envelope.get_crypto_kind(), detail.envelope.get_sender_id());
// Decode the RPC message // Decode the RPC message
let operation = { let operation = {
@ -1208,7 +1208,7 @@ impl RPCProcessor {
.get_root::<veilid_capnp::operation::Reader>() .get_root::<veilid_capnp::operation::Reader>()
.map_err(RPCError::protocol) .map_err(RPCError::protocol)
.map_err(logthru_rpc!())?; .map_err(logthru_rpc!())?;
RPCOperation::decode(&op_reader, Some(&sender_node_id))? RPCOperation::decode(&op_reader, self.crypto.clone())?
}; };
// Get the sender noderef, incorporating sender's peer info // Get the sender noderef, incorporating sender's peer info
@ -1217,14 +1217,14 @@ impl RPCProcessor {
// Ensure the sender peer info is for the actual sender specified in the envelope // Ensure the sender peer info is for the actual sender specified in the envelope
// Sender PeerInfo was specified, update our routing table with it // Sender PeerInfo was specified, update our routing table with it
if !self.filter_node_info(routing_domain, &sender_peer_info) { if !self.filter_node_info(routing_domain, &sender_peer_info.signed_node_info) {
return Err(RPCError::invalid_format( return Err(RPCError::invalid_format(
"sender peerinfo has invalid peer scope", "sender peerinfo has invalid peer scope",
)); ));
} }
opt_sender_nr = self.routing_table().register_node_with_peer_info( opt_sender_nr = self.routing_table().register_node_with_peer_info(
routing_domain, routing_domain,
sender_peer_info, sender_peer_info.clone(),
false, false,
); );
} }
@ -1255,7 +1255,7 @@ impl RPCProcessor {
.get_root::<veilid_capnp::operation::Reader>() .get_root::<veilid_capnp::operation::Reader>()
.map_err(RPCError::protocol) .map_err(RPCError::protocol)
.map_err(logthru_rpc!())?; .map_err(logthru_rpc!())?;
RPCOperation::decode(&op_reader, None)? RPCOperation::decode(&op_reader, self.crypto.clone())?
}; };
// Make the RPC message // Make the RPC message

View File

@ -89,13 +89,6 @@ impl RPCProcessor {
_ => panic!("not a question"), _ => panic!("not a question"),
}; };
// Get the crypto kinds the requesting node is capable of
let crypto_kinds = if let Some(sender_nr) = msg.opt_sender_nr {
sender_nr.node_ids().kinds()
} else {
vec![msg.header.crypto_kind()]
};
// add node information for the requesting node to our routing table // add node information for the requesting node to our routing table
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let Some(own_peer_info) = routing_table.get_own_peer_info(RoutingDomain::PublicInternet) else { let Some(own_peer_info) = routing_table.get_own_peer_info(RoutingDomain::PublicInternet) else {
@ -106,12 +99,6 @@ impl RPCProcessor {
// find N nodes closest to the target node in our routing table // find N nodes closest to the target node in our routing table
let filter = Box::new( let filter = Box::new(
move |rti: &RoutingTableInner, opt_entry: Option<Arc<BucketEntry>>| { move |rti: &RoutingTableInner, opt_entry: Option<Arc<BucketEntry>>| {
// ensure the returned nodes have at least the crypto kind used to send the findnodeq
if let Some(entry) = opt_entry {
if !entry.with(rti, |_rti, e| e.crypto_kinds().contains(&crypto_kind)) {
return false;
}
}
// Ensure only things that are valid/signed in the PublicInternet domain are returned // Ensure only things that are valid/signed in the PublicInternet domain are returned
rti.filter_has_valid_signed_node_info( rti.filter_has_valid_signed_node_info(
RoutingDomain::PublicInternet, RoutingDomain::PublicInternet,

View File

@ -123,18 +123,18 @@ pub async fn test_store_delete_load(ts: TableStore) {
assert_eq!(db.load(2, b"baz").unwrap(), Some(b"QWERTY".to_vec())); assert_eq!(db.load(2, b"baz").unwrap(), Some(b"QWERTY".to_vec()));
} }
pub async fn test_frozen(ts: TableStore) { pub async fn test_frozen(vcrypto: CryptoSystemVersion, ts: TableStore) {
trace!("test_frozen"); trace!("test_frozen");
let _ = ts.delete("test"); let _ = ts.delete("test");
let db = ts.open("test", 3).await.expect("should have opened"); let db = ts.open("test", 3).await.expect("should have opened");
let (dht_key, _) = generate_secret(); let (dht_key, _) = vcrypto.generate_keypair();
assert!(db.store_rkyv(0, b"asdf", &dht_key).await.is_ok()); assert!(db.store_rkyv(0, b"asdf", &dht_key).await.is_ok());
assert_eq!(db.load_rkyv::<TypedKey>(0, b"qwer").unwrap(), None); assert_eq!(db.load_rkyv::<PublicKey>(0, b"qwer").unwrap(), None);
let d = match db.load_rkyv::<TypedKey>(0, b"asdf") { let d = match db.load_rkyv::<PublicKey>(0, b"asdf") {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
panic!("couldn't decode: {}", e); panic!("couldn't decode: {}", e);
@ -155,12 +155,16 @@ pub async fn test_frozen(ts: TableStore) {
pub async fn test_all() { pub async fn test_all() {
let api = startup().await; let api = startup().await;
let crypto = api.crypto().unwrap();
let ts = api.table_store().unwrap(); let ts = api.table_store().unwrap();
for ck in VALID_CRYPTO_KINDS {
let vcrypto = crypto.get(ck).unwrap();
test_delete_open_delete(ts.clone()).await; test_delete_open_delete(ts.clone()).await;
test_store_delete_load(ts.clone()).await; test_store_delete_load(ts.clone()).await;
test_frozen(ts.clone()).await; test_frozen(vcrypto, ts.clone()).await;
let _ = ts.delete("test").await; let _ = ts.delete("test").await;
}
shutdown(api).await; shutdown(api).await;
} }

View File

@ -192,9 +192,18 @@ fn config_callback(key: String) -> ConfigCallbackReturn {
"network.client_whitelist_timeout_ms" => Ok(Box::new(300_000u32)), "network.client_whitelist_timeout_ms" => Ok(Box::new(300_000u32)),
"network.reverse_connection_receipt_time_ms" => Ok(Box::new(5_000u32)), "network.reverse_connection_receipt_time_ms" => Ok(Box::new(5_000u32)),
"network.hole_punch_receipt_time_ms" => Ok(Box::new(5_000u32)), "network.hole_punch_receipt_time_ms" => Ok(Box::new(5_000u32)),
"network.node_id" => Ok(Box::new(Option::<TypedKey>::None)), "network.routing_table.node_ids" => {
"network.node_id_secret" => Ok(Box::new(Option::<SecretKey>::None)), let mut nids = BTreeMap::<CryptoKind, VeilidConfigNodeId>::new();
"network.bootstrap" => Ok(Box::new(Vec::<String>::new())), nids.insert(
CRYPTO_KIND_VLD0,
VeilidConfigNodeId {
node_id: None,
node_id_secret: None,
},
);
Ok(Box::new(nids))
}
"network.routing_table.bootstrap" => Ok(Box::new(Vec::<String>::new())),
"network.routing_table.limit_over_attached" => Ok(Box::new(64u32)), "network.routing_table.limit_over_attached" => Ok(Box::new(64u32)),
"network.routing_table.limit_fully_attached" => Ok(Box::new(32u32)), "network.routing_table.limit_fully_attached" => Ok(Box::new(32u32)),
"network.routing_table.limit_attached_strong" => Ok(Box::new(16u32)), "network.routing_table.limit_attached_strong" => Ok(Box::new(16u32)),
@ -315,14 +324,13 @@ pub async fn test_config() {
assert_eq!(inner.network.client_whitelist_timeout_ms, 300_000u32); assert_eq!(inner.network.client_whitelist_timeout_ms, 300_000u32);
assert_eq!(inner.network.reverse_connection_receipt_time_ms, 5_000u32); assert_eq!(inner.network.reverse_connection_receipt_time_ms, 5_000u32);
assert_eq!(inner.network.hole_punch_receipt_time_ms, 5_000u32); assert_eq!(inner.network.hole_punch_receipt_time_ms, 5_000u32);
assert!(inner.network.node_id.is_none());
assert!(inner.network.node_id_secret.is_none());
assert_eq!(inner.network.bootstrap, Vec::<String>::new());
assert_eq!(inner.network.rpc.concurrency, 2u32); assert_eq!(inner.network.rpc.concurrency, 2u32);
assert_eq!(inner.network.rpc.queue_size, 1024u32); assert_eq!(inner.network.rpc.queue_size, 1024u32);
assert_eq!(inner.network.rpc.timeout_ms, 10_000u32); assert_eq!(inner.network.rpc.timeout_ms, 10_000u32);
assert_eq!(inner.network.rpc.max_route_hop_count, 4u8); assert_eq!(inner.network.rpc.max_route_hop_count, 4u8);
assert_eq!(inner.network.rpc.default_route_hop_count, 1u8); assert_eq!(inner.network.rpc.default_route_hop_count, 1u8);
assert_eq!(inner.network.routing_table.node_ids.len(), 1);
assert_eq!(inner.network.routing_table.bootstrap, Vec::<String>::new());
assert_eq!(inner.network.routing_table.limit_over_attached, 64u32); assert_eq!(inner.network.routing_table.limit_over_attached, 64u32);
assert_eq!(inner.network.routing_table.limit_fully_attached, 32u32); assert_eq!(inner.network.routing_table.limit_fully_attached, 32u32);
assert_eq!(inner.network.routing_table.limit_attached_strong, 16u32); assert_eq!(inner.network.routing_table.limit_attached_strong, 16u32);

View File

@ -50,65 +50,84 @@ pub async fn test_signed_node_info() {
.await .await
.expect("startup failed"); .expect("startup failed");
let crypto = api.crypto().unwrap();
for ck in VALID_CRYPTO_KINDS {
let vcrypto = crypto.get(ck).unwrap();
// Test direct // Test direct
let node_info = NodeInfo { let node_info = NodeInfo {
network_class: NetworkClass::InboundCapable, network_class: NetworkClass::InboundCapable,
outbound_protocols: ProtocolTypeSet::all(), outbound_protocols: ProtocolTypeSet::all(),
address_types: AddressTypeSet::all(), address_types: AddressTypeSet::all(),
min_version: 0, envelope_support: VALID_ENVELOPE_VERSIONS.to_vec(),
max_version: 0, crypto_support: VALID_CRYPTO_KINDS.to_vec(),
dial_info_detail_list: vec![DialInfoDetail { dial_info_detail_list: vec![DialInfoDetail {
class: DialInfoClass::Mapped, class: DialInfoClass::Mapped,
dial_info: DialInfo::udp(SocketAddress::default()), dial_info: DialInfo::udp(SocketAddress::default()),
}], }],
}; };
let (pkey, skey) = generate_secret(); let (pkey, skey) = vcrypto.generate_keypair();
let sni = let sni = SignedDirectNodeInfo::make_signatures(
SignedDirectNodeInfo::with_secret(NodeId::new(pkey.clone()), node_info.clone(), &skey) crypto.clone(),
.unwrap(); vec![TypedKeyPair::new(ck, pkey, skey)],
let _ = SignedDirectNodeInfo::new(
NodeId::new(pkey),
node_info.clone(), node_info.clone(),
sni.timestamp,
sni.signature.unwrap(),
) )
.unwrap(); .unwrap();
let mut tks: TypedKeySet = TypedKey::new(ck, pkey).into();
let oldtkslen = tks.len();
let _ = SignedDirectNodeInfo::new(
crypto.clone(),
&mut tks,
node_info.clone(),
sni.timestamp,
sni.signatures.clone(),
)
.unwrap();
assert_eq!(tks.len(), oldtkslen);
assert_eq!(tks.len(), sni.signatures.len());
// Test relayed // Test relayed
let node_info2 = NodeInfo { let node_info2 = NodeInfo {
network_class: NetworkClass::OutboundOnly, network_class: NetworkClass::OutboundOnly,
outbound_protocols: ProtocolTypeSet::all(), outbound_protocols: ProtocolTypeSet::all(),
address_types: AddressTypeSet::all(), address_types: AddressTypeSet::all(),
min_version: 0, envelope_support: VALID_ENVELOPE_VERSIONS.to_vec(),
max_version: 0, crypto_support: VALID_CRYPTO_KINDS.to_vec(),
dial_info_detail_list: vec![DialInfoDetail { dial_info_detail_list: vec![DialInfoDetail {
class: DialInfoClass::Blocked, class: DialInfoClass::Blocked,
dial_info: DialInfo::udp(SocketAddress::default()), dial_info: DialInfo::udp(SocketAddress::default()),
}], }],
}; };
let (pkey2, skey2) = generate_secret(); let (pkey2, skey2) = vcrypto.generate_keypair();
let mut tks2: TypedKeySet = TypedKey::new(ck, pkey2).into();
let oldtks2len = tks2.len();
let sni2 = SignedRelayedNodeInfo::make_signatures( let sni2 = SignedRelayedNodeInfo::make_signatures(
NodeId::new(pkey2.clone()), crypto.clone(),
vec![TypedKeyPair::new(ck, pkey2, skey2)],
node_info2.clone(), node_info2.clone(),
NodeId::new(pkey.clone()), tks.clone(),
sni.clone(), sni.clone(),
&skey2,
) )
.unwrap(); .unwrap();
let _ = SignedRelayedNodeInfo::new( let _ = SignedRelayedNodeInfo::new(
NodeId::new(pkey2), crypto.clone(),
&mut tks2,
node_info2, node_info2,
NodeId::new(pkey), tks,
sni, sni,
sni2.timestamp, sni2.timestamp,
sni2.signature, sni2.signatures.clone(),
) )
.unwrap(); .unwrap();
assert_eq!(tks2.len(), oldtks2len);
assert_eq!(tks2.len(), sni2.signatures.len());
}
api.shutdown().await; api.shutdown().await;
} }

View File

@ -7,7 +7,7 @@ use routing_table::*;
#[derive(Default, Debug)] #[derive(Default, Debug)]
struct DebugCache { struct DebugCache {
imported_routes: Vec<TypedKey>, imported_routes: Vec<TypedKeySet>,
} }
static DEBUG_CACHE: Mutex<DebugCache> = Mutex::new(DebugCache { static DEBUG_CACHE: Mutex<DebugCache> = Mutex::new(DebugCache {
@ -30,12 +30,12 @@ fn get_string(text: &str) -> Option<String> {
Some(text.to_owned()) Some(text.to_owned())
} }
fn get_route_id(rss: RouteSpecStore) -> impl Fn(&str) -> Option<TypedKey> { fn get_route_id(rss: RouteSpecStore) -> impl Fn(&str) -> Option<PublicKey> {
return move |text: &str| { return move |text: &str| {
if text.is_empty() { if text.is_empty() {
return None; return None;
} }
match TypedKey::from_str(text).ok() { match PublicKey::from_str(text).ok() {
Some(key) => { Some(key) => {
let routes = rss.list_allocated_routes(|k, _| Some(*k)); let routes = rss.list_allocated_routes(|k, _| Some(*k));
if routes.contains(&key) { if routes.contains(&key) {
@ -128,12 +128,31 @@ fn get_destination(routing_table: RoutingTable) -> impl FnOnce(&str) -> Option<D
} }
if &text[0..1] == "#" { if &text[0..1] == "#" {
// Private route // Private route
let text = &text[1..]; let mut text = &text[1..];
let opt_crypto_kind = if text.len() > 5 {
let fcc = &text[0..4];
if &text[4..5] != ":" {
return None;
}
let ck = match FourCC::from_str(fcc) {
Ok(v) => v,
Err(_) => {
return None;
}
};
text = &text[5..];
Some(ck)
} else {
None
};
let n = get_number(text)?; let n = get_number(text)?;
let mut dc = DEBUG_CACHE.lock(); let mut dc = DEBUG_CACHE.lock();
let pr_pubkey = dc.imported_routes.get(n)?; let pr_pubkey = match opt_crypto_kind {
Some(ck) => dc.imported_routes.get(n)?.get(ck)?,
None => dc.imported_routes.get(n)?.best()?,
};
let rss = routing_table.route_spec_store(); let rss = routing_table.route_spec_store();
let Some(private_route) = rss.get_remote_private_route(&pr_pubkey) else { let Some(private_route) = rss.get_remote_private_route(&pr_pubkey.key) else {
// Remove imported route // Remove imported route
dc.imported_routes.remove(n); dc.imported_routes.remove(n);
info!("removed dead imported route {}", n); info!("removed dead imported route {}", n);
@ -150,15 +169,14 @@ fn get_destination(routing_table: RoutingTable) -> impl FnOnce(&str) -> Option<D
.unwrap_or((text, None)); .unwrap_or((text, None));
if let Some((first, second)) = text.split_once('@') { if let Some((first, second)) = text.split_once('@') {
// Relay // Relay
let relay_id = get_typed_key(second)?; let mut relay_nr = get_node_ref(routing_table.clone())(second)?;
let mut relay_nr = routing_table.lookup_node_ref(relay_id)?; let target_nr = get_node_ref(routing_table)(first)?;
let target_id = get_typed_key(first)?;
if let Some(mods) = mods { if let Some(mods) = mods {
relay_nr = get_node_ref_modifiers(relay_nr)(mods)?; relay_nr = get_node_ref_modifiers(relay_nr)(mods)?;
} }
let mut d = Destination::relay(relay_nr, target_id); let mut d = Destination::relay(relay_nr, target_nr);
if let Some(ss) = ss { if let Some(ss) = ss {
d = d.with_safety(ss) d = d.with_safety(ss)
} }
@ -166,8 +184,7 @@ fn get_destination(routing_table: RoutingTable) -> impl FnOnce(&str) -> Option<D
Some(d) Some(d)
} else { } else {
// Direct // Direct
let target_id = get_typed_key(text)?; let mut target_nr = get_node_ref(routing_table)(text)?;
let mut target_nr = routing_table.lookup_node_ref(target_id)?;
if let Some(mods) = mods { if let Some(mods) = mods {
target_nr = get_node_ref_modifiers(target_nr)(mods)?; target_nr = get_node_ref_modifiers(target_nr)(mods)?;
@ -190,6 +207,9 @@ fn get_number(text: &str) -> Option<usize> {
fn get_typed_key(text: &str) -> Option<TypedKey> { fn get_typed_key(text: &str) -> Option<TypedKey> {
TypedKey::from_str(text).ok() TypedKey::from_str(text).ok()
} }
fn get_public_key(text: &str) -> Option<PublicKey> {
PublicKey::from_str(text).ok()
}
fn get_node_ref(routing_table: RoutingTable) -> impl FnOnce(&str) -> Option<NodeRef> { fn get_node_ref(routing_table: RoutingTable) -> impl FnOnce(&str) -> Option<NodeRef> {
move |text| { move |text| {
@ -198,8 +218,13 @@ fn get_node_ref(routing_table: RoutingTable) -> impl FnOnce(&str) -> Option<Node
.map(|x| (x.0, Some(x.1))) .map(|x| (x.0, Some(x.1)))
.unwrap_or((text, None)); .unwrap_or((text, None));
let node_id = get_typed_key(text)?; let mut nr = if let Some(key) = get_public_key(text) {
let mut nr = routing_table.lookup_node_ref(node_id)?; routing_table.lookup_any_node_ref(key)?
} else if let Some(key) = get_typed_key(text) {
routing_table.lookup_node_ref(key)?
} else {
return None;
};
if let Some(mods) = mods { if let Some(mods) = mods {
nr = get_node_ref_modifiers(nr)(mods)?; nr = get_node_ref_modifiers(nr)(mods)?;
} }
@ -607,8 +632,15 @@ impl VeilidAPI {
} }
// Allocate route // Allocate route
let out = match rss.allocate_route(stability, sequencing, hop_count, directions, &[]) { let out = match rss.allocate_route(
Ok(Some(v)) => format!("{}", v.encode()), &VALID_CRYPTO_KINDS,
stability,
sequencing,
hop_count,
directions,
&[],
) {
Ok(Some(v)) => format!("{}", v),
Ok(None) => format!("<unavailable>"), Ok(None) => format!("<unavailable>"),
Err(e) => { Err(e) => {
format!("Route allocation failed: {}", e) format!("Route allocation failed: {}", e)
@ -685,7 +717,7 @@ impl VeilidAPI {
let routing_table = netman.routing_table(); let routing_table = netman.routing_table();
let rss = routing_table.route_spec_store(); let rss = routing_table.route_spec_store();
let route_id = get_debug_argument_at(&args, 1, "debug_route", "route_id", get_typed_key)?; let route_id = get_debug_argument_at(&args, 1, "debug_route", "route_id", get_public_key)?;
// Unpublish route // Unpublish route
let out = if let Err(e) = rss.mark_route_published(&route_id, false) { let out = if let Err(e) = rss.mark_route_published(&route_id, false) {
@ -701,7 +733,7 @@ impl VeilidAPI {
let routing_table = netman.routing_table(); let routing_table = netman.routing_table();
let rss = routing_table.route_spec_store(); let rss = routing_table.route_spec_store();
let route_id = get_debug_argument_at(&args, 1, "debug_route", "route_id", get_typed_key)?; let route_id = get_debug_argument_at(&args, 1, "debug_route", "route_id", get_public_key)?;
match rss.debug_route(&route_id) { match rss.debug_route(&route_id) {
Some(s) => Ok(s), Some(s) => Ok(s),

View File

@ -1842,7 +1842,7 @@ impl MatchesDialInfoFilter for DialInfo {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Signed NodeInfo that can be passed around amongst peers and verifiable /// Signed NodeInfo that can be passed around amongst peers and verifiable
#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)] #[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
#[archive_attr(repr(C), derive(CheckBytes))] #[archive_attr(repr(C), derive(CheckBytes))]
pub struct SignedDirectNodeInfo { pub struct SignedDirectNodeInfo {
@ -1851,6 +1851,8 @@ pub struct SignedDirectNodeInfo {
pub signatures: Vec<TypedSignature>, pub signatures: Vec<TypedSignature>,
} }
impl SignedDirectNodeInfo { impl SignedDirectNodeInfo {
/// Returns a new SignedDirectNodeInfo that has its signatures validated. Will modify the node_ids set to only include node_ids whose signatures validate
/// All signatures are stored however, as this can be passed to other nodes that may be able to validate those signatures.
pub fn new( pub fn new(
crypto: Crypto, crypto: Crypto,
node_ids: &mut TypedKeySet, node_ids: &mut TypedKeySet,
@ -1937,6 +1939,8 @@ pub struct SignedRelayedNodeInfo {
} }
impl SignedRelayedNodeInfo { impl SignedRelayedNodeInfo {
/// Returns a new SignedRelayedNodeInfo that has its signatures validated. Will modify the node_ids set to only include node_ids whose signatures validate
/// All signatures are stored however, as this can be passed to other nodes that may be able to validate those signatures.
pub fn new( pub fn new(
crypto: Crypto, crypto: Crypto,
node_ids: &mut TypedKeySet, node_ids: &mut TypedKeySet,