more capability work
This commit is contained in:
parent
e674eaf496
commit
8f721c428b
@ -190,19 +190,8 @@ struct DialInfoDetail @0x96423aa1d67b74d8 {
|
||||
class @1 :DialInfoClass;
|
||||
}
|
||||
|
||||
struct PublicInternetNodeStatus @0x9c9d7f1f12eb088f {
|
||||
capabilities @0 :List(Capability); # List of Capability FOURCC codes that this node is advertising it is capable of in the publicinternet routing domain
|
||||
}
|
||||
|
||||
struct LocalNetworkNodeStatus @0x957f5bfed2d0b5a5 {
|
||||
capabilities @0 :List(Capability); # List of Capability FOURCC codes that this node is advertising it is capable of in the localnetwork routing domain
|
||||
}
|
||||
|
||||
struct NodeStatus @0xd36b9e7a3bf3330d {
|
||||
union {
|
||||
publicInternet @0 :PublicInternetNodeStatus;
|
||||
localNetwork @1 :LocalNetworkNodeStatus;
|
||||
}
|
||||
# Reserved for non-nodeinfo status
|
||||
}
|
||||
|
||||
struct ProtocolTypeSet @0x82f12f55a1b73326 {
|
||||
@ -227,7 +216,8 @@ struct NodeInfo @0xe125d847e3f9f419 {
|
||||
addressTypes @2 :AddressTypeSet; # address types supported
|
||||
envelopeSupport @3 :List(UInt8); # supported rpc envelope/receipt versions
|
||||
cryptoSupport @4 :List(CryptoKind); # cryptography systems supported
|
||||
dialInfoDetailList @5 :List(DialInfoDetail); # inbound dial info details for this node
|
||||
capabilities @5 :List(Capability); # capabilities supported by the node
|
||||
dialInfoDetailList @6 :List(DialInfoDetail); # inbound dial info details for this node
|
||||
}
|
||||
|
||||
struct SignedDirectNodeInfo @0xe0e7ea3e893a3dd7 {
|
||||
|
@ -5,31 +5,31 @@ mod native;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod wasm;
|
||||
|
||||
mod direct_boot;
|
||||
mod send_data;
|
||||
mod connection_handle;
|
||||
mod address_filter;
|
||||
mod connection_handle;
|
||||
mod connection_manager;
|
||||
mod connection_table;
|
||||
mod direct_boot;
|
||||
mod network_connection;
|
||||
mod send_data;
|
||||
mod stats;
|
||||
mod tasks;
|
||||
mod types;
|
||||
mod stats;
|
||||
|
||||
pub mod tests;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub use connection_manager::*;
|
||||
pub use network_connection::*;
|
||||
pub use types::*;
|
||||
pub use send_data::*;
|
||||
pub use direct_boot::*;
|
||||
pub use network_connection::*;
|
||||
pub use send_data::*;
|
||||
pub use stats::*;
|
||||
pub use types::*;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
use connection_handle::*;
|
||||
use address_filter::*;
|
||||
use connection_handle::*;
|
||||
use crypto::*;
|
||||
use futures_util::stream::FuturesUnordered;
|
||||
use hashlink::LruCache;
|
||||
@ -47,13 +47,16 @@ use wasm::*;
|
||||
|
||||
pub const MAX_MESSAGE_SIZE: usize = MAX_ENVELOPE_SIZE;
|
||||
pub const IPADDR_TABLE_SIZE: usize = 1024;
|
||||
pub const IPADDR_MAX_INACTIVE_DURATION_US: TimestampDuration = TimestampDuration::new(300_000_000u64); // 5 minutes
|
||||
pub const IPADDR_MAX_INACTIVE_DURATION_US: TimestampDuration =
|
||||
TimestampDuration::new(300_000_000u64); // 5 minutes
|
||||
pub const NODE_CONTACT_METHOD_CACHE_SIZE: usize = 1024;
|
||||
pub const PUBLIC_ADDRESS_CHANGE_DETECTION_COUNT: usize = 3;
|
||||
pub const PUBLIC_ADDRESS_CHECK_CACHE_SIZE: usize = 8;
|
||||
pub const PUBLIC_ADDRESS_CHECK_TASK_INTERVAL_SECS: u32 = 60;
|
||||
pub const PUBLIC_ADDRESS_INCONSISTENCY_TIMEOUT_US: TimestampDuration = TimestampDuration::new(300_000_000u64); // 5 minutes
|
||||
pub const PUBLIC_ADDRESS_INCONSISTENCY_PUNISHMENT_TIMEOUT_US: TimestampDuration = TimestampDuration::new(3600_000_000u64); // 60 minutes
|
||||
pub const PUBLIC_ADDRESS_INCONSISTENCY_TIMEOUT_US: TimestampDuration =
|
||||
TimestampDuration::new(300_000_000u64); // 5 minutes
|
||||
pub const PUBLIC_ADDRESS_INCONSISTENCY_PUNISHMENT_TIMEOUT_US: TimestampDuration =
|
||||
TimestampDuration::new(3600_000_000u64); // 60 minutes
|
||||
pub const ADDRESS_FILTER_TASK_INTERVAL_SECS: u32 = 60;
|
||||
pub const BOOT_MAGIC: &[u8; 4] = b"BOOT";
|
||||
|
||||
@ -75,7 +78,6 @@ struct NetworkComponents {
|
||||
receipt_manager: ReceiptManager,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ClientWhitelistEntry {
|
||||
last_seen_ts: Timestamp,
|
||||
@ -171,8 +173,7 @@ impl NetworkManager {
|
||||
storage_manager: StorageManager,
|
||||
protected_store: ProtectedStore,
|
||||
table_store: TableStore,
|
||||
#[cfg(feature="unstable-blockstore")]
|
||||
block_store: BlockStore,
|
||||
#[cfg(feature = "unstable-blockstore")] block_store: BlockStore,
|
||||
crypto: Crypto,
|
||||
network_key: Option<SharedSecret>,
|
||||
) -> NetworkManagerUnlockedInner {
|
||||
@ -200,18 +201,20 @@ impl NetworkManager {
|
||||
storage_manager: StorageManager,
|
||||
protected_store: ProtectedStore,
|
||||
table_store: TableStore,
|
||||
#[cfg(feature="unstable-blockstore")]
|
||||
block_store: BlockStore,
|
||||
#[cfg(feature = "unstable-blockstore")] block_store: BlockStore,
|
||||
crypto: Crypto,
|
||||
) -> Self {
|
||||
|
||||
// Make the network key
|
||||
let network_key = {
|
||||
let c = config.get();
|
||||
let network_key_password = if let Some(nkp) = c.network.network_key_password.clone() {
|
||||
Some(nkp)
|
||||
} else {
|
||||
if c.network.routing_table.bootstrap.contains(&"bootstrap.veilid.net".to_owned()) {
|
||||
if c.network
|
||||
.routing_table
|
||||
.bootstrap
|
||||
.contains(&"bootstrap.veilid.net".to_owned())
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(c.network.routing_table.bootstrap.join(","))
|
||||
@ -224,7 +227,13 @@ impl NetworkManager {
|
||||
|
||||
let bcs = crypto.best();
|
||||
// Yes the use of the salt this way is generally bad, but this just needs to be hashed
|
||||
Some(bcs.derive_shared_secret(network_key_password.as_bytes(), network_key_password.as_bytes()).expect("failed to derive network key"))
|
||||
Some(
|
||||
bcs.derive_shared_secret(
|
||||
network_key_password.as_bytes(),
|
||||
network_key_password.as_bytes(),
|
||||
)
|
||||
.expect("failed to derive network key"),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -475,7 +484,8 @@ impl NetworkManager {
|
||||
pub fn purge_client_whitelist(&self) {
|
||||
let timeout_ms = self.with_config(|c| c.network.client_whitelist_timeout_ms);
|
||||
let mut inner = self.inner.lock();
|
||||
let cutoff_timestamp = get_aligned_timestamp() - TimestampDuration::new((timeout_ms as u64) * 1000u64);
|
||||
let cutoff_timestamp =
|
||||
get_aligned_timestamp() - TimestampDuration::new((timeout_ms as u64) * 1000u64);
|
||||
// Remove clients from the whitelist that haven't been since since our whitelist timeout
|
||||
while inner
|
||||
.client_whitelist
|
||||
@ -493,95 +503,8 @@ impl NetworkManager {
|
||||
net.needs_restart()
|
||||
}
|
||||
|
||||
/// Get our node's capabilities in the PublicInternet routing domain
|
||||
fn generate_public_internet_node_status(&self) -> PublicInternetNodeStatus {
|
||||
|
||||
let Some(own_peer_info) = self
|
||||
.routing_table()
|
||||
.get_own_peer_info(RoutingDomain::PublicInternet) else {
|
||||
return PublicInternetNodeStatus::default();
|
||||
};
|
||||
let own_node_info = own_peer_info.signed_node_info().node_info();
|
||||
|
||||
let config = self.config();
|
||||
let c = config.get();
|
||||
|
||||
let will_route = own_node_info.can_inbound_relay(); // xxx: eventually this may have more criteria added
|
||||
let will_tunnel = own_node_info.can_inbound_relay(); // xxx: we may want to restrict by battery life and network bandwidth at some point
|
||||
let will_signal = own_node_info.can_signal();
|
||||
let will_relay = own_node_info.can_inbound_relay();
|
||||
let will_validate_dial_info = own_node_info.can_validate_dial_info();
|
||||
|
||||
let mut capabilities = Vec::new();
|
||||
if will_route && !c.capabilities.disable.contains(&CAP_WILL_ROUTE) {
|
||||
capabilities.push(CAP_WILL_ROUTE);
|
||||
}
|
||||
if will_tunnel && !c.capabilities.disable.contains(&CAP_WILL_TUNNEL) {
|
||||
capabilities.push(CAP_WILL_TUNNEL);
|
||||
}
|
||||
if will_signal && !c.capabilities.disable.contains(&CAP_WILL_SIGNAL) {
|
||||
capabilities.push(CAP_WILL_SIGNAL);
|
||||
}
|
||||
if will_relay && !c.capabilities.disable.contains(&CAP_WILL_RELAY){
|
||||
capabilities.push(CAP_WILL_RELAY);
|
||||
}
|
||||
if will_validate_dial_info && !c.capabilities.disable.contains(&CAP_WILL_VALIDATE_DIAL_INFO) {
|
||||
capabilities.push(CAP_WILL_VALIDATE_DIAL_INFO);
|
||||
}
|
||||
if !c.capabilities.disable.contains(&CAP_WILL_DHT) {
|
||||
capabilities.push(CAP_WILL_DHT);
|
||||
}
|
||||
if !c.capabilities.disable.contains(&CAP_WILL_APPMESSAGE) {
|
||||
capabilities.push(CAP_WILL_APPMESSAGE);
|
||||
}
|
||||
|
||||
PublicInternetNodeStatus {
|
||||
capabilities
|
||||
}
|
||||
}
|
||||
/// Get our node's capabilities in the LocalNetwork routing domain
|
||||
fn generate_local_network_node_status(&self) -> LocalNetworkNodeStatus {
|
||||
let Some(own_peer_info) = self
|
||||
.routing_table()
|
||||
.get_own_peer_info(RoutingDomain::LocalNetwork) else {
|
||||
return LocalNetworkNodeStatus::default();
|
||||
};
|
||||
|
||||
let own_node_info = own_peer_info.signed_node_info().node_info();
|
||||
|
||||
let config = self.config();
|
||||
let c = config.get();
|
||||
|
||||
let will_relay = own_node_info.can_inbound_relay();
|
||||
let will_validate_dial_info = own_node_info.can_validate_dial_info();
|
||||
|
||||
let mut capabilities = Vec::new();
|
||||
if will_relay && !c.capabilities.disable.contains(&CAP_WILL_RELAY) {
|
||||
capabilities.push(CAP_WILL_RELAY);
|
||||
}
|
||||
if will_validate_dial_info && !c.capabilities.disable.contains(&CAP_WILL_VALIDATE_DIAL_INFO) {
|
||||
capabilities.push(CAP_WILL_VALIDATE_DIAL_INFO);
|
||||
}
|
||||
if !c.capabilities.disable.contains(&CAP_WILL_DHT) {
|
||||
capabilities.push(CAP_WILL_DHT);
|
||||
}
|
||||
if !c.capabilities.disable.contains(&CAP_WILL_APPMESSAGE) {
|
||||
capabilities.push(CAP_WILL_APPMESSAGE);
|
||||
}
|
||||
LocalNetworkNodeStatus {
|
||||
capabilities
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_node_status(&self, routing_domain: RoutingDomain) -> NodeStatus {
|
||||
match routing_domain {
|
||||
RoutingDomain::PublicInternet => {
|
||||
NodeStatus::PublicInternet(self.generate_public_internet_node_status())
|
||||
}
|
||||
RoutingDomain::LocalNetwork => {
|
||||
NodeStatus::LocalNetwork(self.generate_local_network_node_status())
|
||||
}
|
||||
}
|
||||
pub fn generate_node_status(&self, _routing_domain: RoutingDomain) -> NodeStatus {
|
||||
NodeStatus {}
|
||||
}
|
||||
|
||||
/// Generates a multi-shot/normal receipt
|
||||
@ -603,7 +526,13 @@ impl NetworkManager {
|
||||
let node_id = routing_table.node_id(vcrypto.kind());
|
||||
let node_id_secret = routing_table.node_id_secret_key(vcrypto.kind());
|
||||
|
||||
let receipt = Receipt::try_new(best_envelope_version(), node_id.kind, nonce, node_id.value, extra_data)?;
|
||||
let receipt = Receipt::try_new(
|
||||
best_envelope_version(),
|
||||
node_id.kind,
|
||||
nonce,
|
||||
node_id.value,
|
||||
extra_data,
|
||||
)?;
|
||||
let out = receipt
|
||||
.to_signed_data(self.crypto(), &node_id_secret)
|
||||
.wrap_err("failed to generate signed receipt")?;
|
||||
@ -632,7 +561,13 @@ impl NetworkManager {
|
||||
let node_id = routing_table.node_id(vcrypto.kind());
|
||||
let node_id_secret = routing_table.node_id_secret_key(vcrypto.kind());
|
||||
|
||||
let receipt = Receipt::try_new(best_envelope_version(), node_id.kind, nonce, node_id.value, extra_data)?;
|
||||
let receipt = Receipt::try_new(
|
||||
best_envelope_version(),
|
||||
node_id.kind,
|
||||
nonce,
|
||||
node_id.value,
|
||||
extra_data,
|
||||
)?;
|
||||
let out = receipt
|
||||
.to_signed_data(self.crypto(), &node_id_secret)
|
||||
.wrap_err("failed to generate signed receipt")?;
|
||||
@ -744,9 +679,10 @@ impl NetworkManager {
|
||||
) {
|
||||
Ok(nr) => nr,
|
||||
Err(e) => {
|
||||
return Ok(NetworkResult::invalid_message(
|
||||
format!("unable to register reverse connect peerinfo: {}", e)
|
||||
));
|
||||
return Ok(NetworkResult::invalid_message(format!(
|
||||
"unable to register reverse connect peerinfo: {}",
|
||||
e
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
@ -767,9 +703,10 @@ impl NetworkManager {
|
||||
) {
|
||||
Ok(nr) => nr,
|
||||
Err(e) => {
|
||||
return Ok(NetworkResult::invalid_message(
|
||||
format!("unable to register hole punch connect peerinfo: {}", e)
|
||||
));
|
||||
return Ok(NetworkResult::invalid_message(format!(
|
||||
"unable to register hole punch connect peerinfo: {}",
|
||||
e
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
@ -813,7 +750,10 @@ impl NetworkManager {
|
||||
}
|
||||
|
||||
/// Builds an envelope for sending over the network
|
||||
#[cfg_attr(feature="verbose-tracing", instrument(level = "trace", skip(self, body), err))]
|
||||
#[cfg_attr(
|
||||
feature = "verbose-tracing",
|
||||
instrument(level = "trace", skip(self, body), err)
|
||||
)]
|
||||
fn build_envelope<B: AsRef<[u8]>>(
|
||||
&self,
|
||||
dest_node_id: TypedKey,
|
||||
@ -834,9 +774,21 @@ impl NetworkManager {
|
||||
let nonce = vcrypto.random_nonce();
|
||||
|
||||
// Encode envelope
|
||||
let envelope = Envelope::new(version, node_id.kind, ts, nonce, node_id.value, dest_node_id.value);
|
||||
let envelope = Envelope::new(
|
||||
version,
|
||||
node_id.kind,
|
||||
ts,
|
||||
nonce,
|
||||
node_id.value,
|
||||
dest_node_id.value,
|
||||
);
|
||||
envelope
|
||||
.to_encrypted_data(self.crypto(), body.as_ref(), &node_id_secret, &self.unlocked_inner.network_key)
|
||||
.to_encrypted_data(
|
||||
self.crypto(),
|
||||
body.as_ref(),
|
||||
&node_id_secret,
|
||||
&self.unlocked_inner.network_key,
|
||||
)
|
||||
.wrap_err("envelope failed to encode")
|
||||
}
|
||||
|
||||
@ -844,14 +796,16 @@ impl NetworkManager {
|
||||
/// node_ref is the direct destination to which the envelope will be sent
|
||||
/// If 'destination_node_ref' is specified, it can be different than the node_ref being sent to
|
||||
/// which will cause the envelope to be relayed
|
||||
#[cfg_attr(feature="verbose-tracing", instrument(level = "trace", skip(self, body), ret, err))]
|
||||
#[cfg_attr(
|
||||
feature = "verbose-tracing",
|
||||
instrument(level = "trace", skip(self, body), ret, err)
|
||||
)]
|
||||
pub async fn send_envelope<B: AsRef<[u8]>>(
|
||||
&self,
|
||||
node_ref: NodeRef,
|
||||
destination_node_ref: Option<NodeRef>,
|
||||
body: B,
|
||||
) -> EyreResult<NetworkResult<SendDataKind>> {
|
||||
|
||||
let destination_node_ref = destination_node_ref.as_ref().unwrap_or(&node_ref).clone();
|
||||
|
||||
if !node_ref.same_entry(&destination_node_ref) {
|
||||
@ -934,10 +888,7 @@ impl NetworkManager {
|
||||
let remote_addr = connection_descriptor.remote_address().to_ip_addr();
|
||||
|
||||
// Network accounting
|
||||
self.stats_packet_rcvd(
|
||||
remote_addr,
|
||||
ByteCount::new(data.len() as u64),
|
||||
);
|
||||
self.stats_packet_rcvd(remote_addr, ByteCount::new(data.len() as u64));
|
||||
|
||||
// If this is a zero length packet, just drop it, because these are used for hole punching
|
||||
// and possibly other low-level network connectivity tasks and will never require
|
||||
@ -978,7 +929,9 @@ impl NetworkManager {
|
||||
}
|
||||
|
||||
// Decode envelope header (may fail signature validation)
|
||||
let envelope = match Envelope::from_signed_data(self.crypto(), data, &self.unlocked_inner.network_key) {
|
||||
let envelope =
|
||||
match Envelope::from_signed_data(self.crypto(), data, &self.unlocked_inner.network_key)
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
log_net!(debug "envelope failed to decode: {}", e);
|
||||
@ -990,8 +943,16 @@ impl NetworkManager {
|
||||
// Get timestamp range
|
||||
let (tsbehind, tsahead) = self.with_config(|c| {
|
||||
(
|
||||
c.network.rpc.max_timestamp_behind_ms.map(ms_to_us).map(TimestampDuration::new),
|
||||
c.network.rpc.max_timestamp_ahead_ms.map(ms_to_us).map(TimestampDuration::new),
|
||||
c.network
|
||||
.rpc
|
||||
.max_timestamp_behind_ms
|
||||
.map(ms_to_us)
|
||||
.map(TimestampDuration::new),
|
||||
c.network
|
||||
.rpc
|
||||
.max_timestamp_ahead_ms
|
||||
.map(ms_to_us)
|
||||
.map(TimestampDuration::new),
|
||||
)
|
||||
});
|
||||
|
||||
@ -1034,7 +995,10 @@ 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, SafetySelection::Unsafe(Sequencing::default())).await {
|
||||
match rpc
|
||||
.resolve_node(recipient_id, SafetySelection::Unsafe(Sequencing::default()))
|
||||
.await
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
log_net!(debug "failed to resolve recipient node for relay, dropping outbound relayed packet: {}" ,e);
|
||||
@ -1093,8 +1057,12 @@ impl NetworkManager {
|
||||
let node_id_secret = routing_table.node_id_secret_key(envelope.get_crypto_kind());
|
||||
|
||||
// Decrypt the envelope body
|
||||
let body = match envelope
|
||||
.decrypt_body(self.crypto(), data, &node_id_secret, &self.unlocked_inner.network_key) {
|
||||
let body = match envelope.decrypt_body(
|
||||
self.crypto(),
|
||||
data,
|
||||
&node_id_secret,
|
||||
&self.unlocked_inner.network_key,
|
||||
) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
log_net!(debug "failed to decrypt envelope body: {}",e);
|
||||
@ -1253,8 +1221,8 @@ impl NetworkManager {
|
||||
.public_address_inconsistencies_table
|
||||
.entry(key)
|
||||
.or_insert_with(|| HashMap::new());
|
||||
let exp_ts =
|
||||
get_aligned_timestamp() + PUBLIC_ADDRESS_INCONSISTENCY_PUNISHMENT_TIMEOUT_US;
|
||||
let exp_ts = get_aligned_timestamp()
|
||||
+ PUBLIC_ADDRESS_INCONSISTENCY_PUNISHMENT_TIMEOUT_US;
|
||||
for i in inconsistencies {
|
||||
pait.insert(i, exp_ts);
|
||||
}
|
||||
@ -1325,5 +1293,4 @@ impl NetworkManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -773,16 +773,34 @@ impl Network {
|
||||
|
||||
// set up the routing table's network config
|
||||
// if we have static public dialinfo, upgrade our network class
|
||||
let public_internet_capabilities = {
|
||||
let c = self.config.get();
|
||||
PUBLIC_INTERNET_CAPABILITIES
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|cap| !c.capabilities.disable.contains(cap))
|
||||
.collect::<Vec<Capability>>()
|
||||
};
|
||||
let local_network_capabilities = {
|
||||
let c = self.config.get();
|
||||
LOCAL_NETWORK_CAPABILITIES
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|cap| !c.capabilities.disable.contains(cap))
|
||||
.collect::<Vec<Capability>>()
|
||||
};
|
||||
|
||||
editor_public_internet.setup_network(
|
||||
protocol_config.outbound,
|
||||
protocol_config.inbound,
|
||||
protocol_config.family_global,
|
||||
public_internet_capabilities,
|
||||
);
|
||||
editor_local_network.setup_network(
|
||||
protocol_config.outbound,
|
||||
protocol_config.inbound,
|
||||
protocol_config.family_local,
|
||||
local_network_capabilities,
|
||||
);
|
||||
let detect_address_changes = {
|
||||
let c = self.config.get();
|
||||
|
@ -20,6 +20,7 @@ pub async fn test_signed_node_info() {
|
||||
AddressTypeSet::all(),
|
||||
VALID_ENVELOPE_VERSIONS.to_vec(),
|
||||
VALID_CRYPTO_KINDS.to_vec(),
|
||||
PUBLIC_INTERNET_CAPABILITIES.to_vec(),
|
||||
vec![DialInfoDetail {
|
||||
class: DialInfoClass::Mapped,
|
||||
dial_info: DialInfo::udp(SocketAddress::default()),
|
||||
@ -75,6 +76,7 @@ pub async fn test_signed_node_info() {
|
||||
AddressTypeSet::all(),
|
||||
VALID_ENVELOPE_VERSIONS.to_vec(),
|
||||
VALID_CRYPTO_KINDS.to_vec(),
|
||||
PUBLIC_INTERNET_CAPABILITIES.to_vec(),
|
||||
vec![DialInfoDetail {
|
||||
class: DialInfoClass::Blocked,
|
||||
dial_info: DialInfo::udp(SocketAddress::default()),
|
||||
|
@ -51,7 +51,7 @@ pub struct BucketEntryPublicInternet {
|
||||
/// The last node info timestamp of ours that this entry has seen
|
||||
last_seen_our_node_info_ts: Timestamp,
|
||||
/// Last known node status
|
||||
node_status: Option<PublicInternetNodeStatus>,
|
||||
node_status: Option<NodeStatus>,
|
||||
}
|
||||
|
||||
/// Bucket entry information specific to the LocalNetwork RoutingDomain
|
||||
@ -63,7 +63,7 @@ pub struct BucketEntryLocalNetwork {
|
||||
/// The last node info timestamp of ours that this entry has seen
|
||||
last_seen_our_node_info_ts: Timestamp,
|
||||
/// Last known node status
|
||||
node_status: Option<LocalNetworkNodeStatus>,
|
||||
node_status: Option<NodeStatus>,
|
||||
}
|
||||
|
||||
/// The data associated with each bucket entry
|
||||
@ -502,13 +502,13 @@ impl BucketEntryInner {
|
||||
&self.peer_stats
|
||||
}
|
||||
|
||||
pub fn update_node_status(&mut self, status: NodeStatus) {
|
||||
match status {
|
||||
NodeStatus::LocalNetwork(ln) => {
|
||||
self.local_network.node_status = Some(ln);
|
||||
pub fn update_node_status(&mut self, routing_domain: RoutingDomain, status: NodeStatus) {
|
||||
match routing_domain {
|
||||
RoutingDomain::LocalNetwork => {
|
||||
self.local_network.node_status = Some(status);
|
||||
}
|
||||
NodeStatus::PublicInternet(pi) => {
|
||||
self.public_internet.node_status = Some(pi);
|
||||
RoutingDomain::PublicInternet => {
|
||||
self.public_internet.node_status = Some(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -518,12 +518,12 @@ impl BucketEntryInner {
|
||||
.local_network
|
||||
.node_status
|
||||
.as_ref()
|
||||
.map(|ln| NodeStatus::LocalNetwork(ln.clone())),
|
||||
.map(|ns| ns.clone()),
|
||||
RoutingDomain::PublicInternet => self
|
||||
.public_internet
|
||||
.node_status
|
||||
.as_ref()
|
||||
.map(|pi| NodeStatus::PublicInternet(pi.clone())),
|
||||
.map(|ns| ns.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,9 +118,9 @@ pub trait NodeRefBase: Sized {
|
||||
fn set_updated_since_last_network_change(&self) {
|
||||
self.operate_mut(|_rti, e| e.set_updated_since_last_network_change(true));
|
||||
}
|
||||
fn update_node_status(&self, node_status: NodeStatus) {
|
||||
fn update_node_status(&self, routing_domain: RoutingDomain, node_status: NodeStatus) {
|
||||
self.operate_mut(|_rti, e| {
|
||||
e.update_node_status(node_status);
|
||||
e.update_node_status(routing_domain, node_status);
|
||||
});
|
||||
}
|
||||
fn envelope_support(&self) -> Vec<u8> {
|
||||
|
@ -257,20 +257,9 @@ impl RouteSpecStore {
|
||||
|
||||
// Exclude nodes with no publicinternet nodeinfo, or incompatible nodeinfo or node status won't route
|
||||
entry.with_inner(|e| {
|
||||
let node_info_ok =
|
||||
if let Some(sni) = e.signed_node_info(RoutingDomain::PublicInternet) {
|
||||
sni.has_sequencing_matched_dial_info(sequencing)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let node_status_ok =
|
||||
if let Some(ns) = e.node_status(RoutingDomain::PublicInternet) {
|
||||
ns.has_capability(CAP_WILL_ROUTE)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
node_info_ok && node_status_ok
|
||||
e.signed_node_info(RoutingDomain::PublicInternet).map(|sni|
|
||||
sni.has_sequencing_matched_dial_info(sequencing) && sni.node_info().can_route()
|
||||
).unwrap_or(false)
|
||||
})
|
||||
},
|
||||
) as RoutingTableEntryFilter;
|
||||
|
@ -13,6 +13,7 @@ enum RoutingDomainChange {
|
||||
outbound_protocols: ProtocolTypeSet,
|
||||
inbound_protocols: ProtocolTypeSet,
|
||||
address_types: AddressTypeSet,
|
||||
capabilities: Vec<Capability>,
|
||||
},
|
||||
SetNetworkClass {
|
||||
network_class: Option<NetworkClass>,
|
||||
@ -79,11 +80,13 @@ impl RoutingDomainEditor {
|
||||
outbound_protocols: ProtocolTypeSet,
|
||||
inbound_protocols: ProtocolTypeSet,
|
||||
address_types: AddressTypeSet,
|
||||
capabilities: Vec<Capability>,
|
||||
) {
|
||||
self.changes.push(RoutingDomainChange::SetupNetwork {
|
||||
outbound_protocols,
|
||||
inbound_protocols,
|
||||
address_types,
|
||||
capabilities,
|
||||
})
|
||||
}
|
||||
|
||||
@ -142,27 +145,32 @@ impl RoutingDomainEditor {
|
||||
outbound_protocols,
|
||||
inbound_protocols,
|
||||
address_types,
|
||||
capabilities,
|
||||
} => {
|
||||
let old_outbound_protocols = detail.common().outbound_protocols();
|
||||
let old_inbound_protocols = detail.common().inbound_protocols();
|
||||
let old_address_types = detail.common().address_types();
|
||||
let old_capabilities = detail.common().capabilities();
|
||||
|
||||
let this_changed = old_outbound_protocols != outbound_protocols
|
||||
|| old_inbound_protocols != inbound_protocols
|
||||
|| old_address_types != address_types;
|
||||
|| old_address_types != address_types
|
||||
|| old_capabilities != capabilities;
|
||||
|
||||
debug!(
|
||||
"[{:?}] setup network: {:?} {:?} {:?}",
|
||||
"[{:?}] setup network: {:?} {:?} {:?} {:?}",
|
||||
self.routing_domain,
|
||||
outbound_protocols,
|
||||
inbound_protocols,
|
||||
address_types
|
||||
address_types,
|
||||
capabilities
|
||||
);
|
||||
|
||||
detail.common_mut().setup_network(
|
||||
outbound_protocols,
|
||||
inbound_protocols,
|
||||
address_types,
|
||||
capabilities,
|
||||
);
|
||||
if this_changed {
|
||||
changed = true;
|
||||
|
@ -27,6 +27,7 @@ pub struct RoutingDomainDetailCommon {
|
||||
inbound_protocols: ProtocolTypeSet,
|
||||
address_types: AddressTypeSet,
|
||||
relay_node: Option<NodeRef>,
|
||||
capabilities: Vec<Capability>,
|
||||
dial_info_details: Vec<DialInfoDetail>,
|
||||
// caches
|
||||
cached_peer_info: Mutex<Option<PeerInfo>>,
|
||||
@ -41,6 +42,7 @@ impl RoutingDomainDetailCommon {
|
||||
inbound_protocols: Default::default(),
|
||||
address_types: Default::default(),
|
||||
relay_node: Default::default(),
|
||||
capabilities: Default::default(),
|
||||
dial_info_details: Default::default(),
|
||||
cached_peer_info: Mutex::new(Default::default()),
|
||||
}
|
||||
@ -52,10 +54,12 @@ impl RoutingDomainDetailCommon {
|
||||
outbound_protocols: ProtocolTypeSet,
|
||||
inbound_protocols: ProtocolTypeSet,
|
||||
address_types: AddressTypeSet,
|
||||
capabilities: Vec<Capability>,
|
||||
) {
|
||||
self.outbound_protocols = outbound_protocols;
|
||||
self.inbound_protocols = inbound_protocols;
|
||||
self.address_types = address_types;
|
||||
self.capabilities = capabilities;
|
||||
self.clear_cache();
|
||||
}
|
||||
|
||||
@ -75,6 +79,9 @@ impl RoutingDomainDetailCommon {
|
||||
pub fn address_types(&self) -> AddressTypeSet {
|
||||
self.address_types
|
||||
}
|
||||
pub fn capabilities(&self) -> Vec<Capability> {
|
||||
self.capabilities.clone()
|
||||
}
|
||||
pub fn relay_node(&self) -> Option<NodeRef> {
|
||||
self.relay_node.clone()
|
||||
}
|
||||
@ -108,6 +115,7 @@ impl RoutingDomainDetailCommon {
|
||||
self.address_types,
|
||||
VALID_ENVELOPE_VERSIONS.to_vec(),
|
||||
VALID_CRYPTO_KINDS.to_vec(),
|
||||
self.capabilities.clone(),
|
||||
self.dial_info_details.clone()
|
||||
);
|
||||
|
||||
|
@ -344,6 +344,7 @@ impl RoutingTable {
|
||||
AddressTypeSet::all(), // Bootstraps are always IPV4 and IPV6 capable
|
||||
bsrec.envelope_support, // Envelope support is as specified in the bootstrap list
|
||||
crypto_support, // Crypto support is derived from list of node ids
|
||||
vec![], // Bootstrap needs no capabilities
|
||||
bsrec.dial_info_details, // Dial info is as specified in the bootstrap list
|
||||
)));
|
||||
|
||||
|
@ -146,9 +146,9 @@ impl RoutingTable {
|
||||
let entry2 = entry.clone();
|
||||
entry.with(rti, |rti, e| {
|
||||
// Ensure we have the node's status
|
||||
if let Some(node_status) = e.node_status(routing_domain) {
|
||||
if let Some(node_info) = e.node_info(routing_domain) {
|
||||
// Ensure the node will relay
|
||||
if node_status.has_capability(CAP_WILL_RELAY) {
|
||||
if node_info.can_inbound_relay() {
|
||||
// Compare against previous candidate
|
||||
if let Some(best_inbound_relay) = best_inbound_relay.as_mut() {
|
||||
// Less is faster
|
||||
|
@ -100,6 +100,7 @@ pub async fn test_round_trip_peerinfo() {
|
||||
AddressTypeSet::new(),
|
||||
vec![0],
|
||||
vec![CRYPTO_KIND_VLD0],
|
||||
PUBLIC_INTERNET_CAPABILITIES.to_vec(),
|
||||
vec![],
|
||||
),
|
||||
Timestamp::new(0),
|
||||
|
@ -1,5 +1,54 @@
|
||||
use super::*;
|
||||
|
||||
pub type Capability = FourCC;
|
||||
pub const CAP_WILL_ROUTE: Capability = FourCC(*b"ROUT");
|
||||
#[cfg(feature = "unstable-tunnels")]
|
||||
pub const CAP_WILL_TUNNEL: Capability = FourCC(*b"TUNL");
|
||||
pub const CAP_WILL_SIGNAL: Capability = FourCC(*b"SGNL");
|
||||
pub const CAP_WILL_RELAY: Capability = FourCC(*b"RLAY");
|
||||
pub const CAP_WILL_VALIDATE_DIAL_INFO: Capability = FourCC(*b"DIAL");
|
||||
pub const CAP_WILL_DHT: Capability = FourCC(*b"DHTV");
|
||||
pub const CAP_WILL_APPMESSAGE: Capability = FourCC(*b"APPM");
|
||||
#[cfg(feature = "unstable-blockstore")]
|
||||
pub const CAP_WILL_BLOCKSTORE: Capability = FourCC(*b"BLOC");
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(all(feature = "unstable-blockstore", feature="unstable-tunnels"))] {
|
||||
const PUBLIC_INTERNET_CAPABILITIES_LEN: usize = 8;
|
||||
} else if #[cfg(any(feature = "unstable-blockstore", feature="unstable-tunnels"))] {
|
||||
const PUBLIC_INTERNET_CAPABILITIES_LEN: usize = 7;
|
||||
} else {
|
||||
const PUBLIC_INTERNET_CAPABILITIES_LEN: usize = 6;
|
||||
}
|
||||
}
|
||||
pub const PUBLIC_INTERNET_CAPABILITIES: [Capability; PUBLIC_INTERNET_CAPABILITIES_LEN] = [
|
||||
CAP_WILL_ROUTE,
|
||||
#[cfg(feature = "unstable-tunnels")]
|
||||
CAP_WILL_TUNNEL,
|
||||
CAP_WILL_SIGNAL,
|
||||
CAP_WILL_RELAY,
|
||||
CAP_WILL_VALIDATE_DIAL_INFO,
|
||||
CAP_WILL_DHT,
|
||||
CAP_WILL_APPMESSAGE,
|
||||
#[cfg(feature = "unstable-blockstore")]
|
||||
CAP_WILL_BLOCKSTORE,
|
||||
];
|
||||
|
||||
#[cfg(feature = "unstable-blockstore")]
|
||||
const LOCAL_NETWORK_CAPABILITIES_LEN: usize = 4;
|
||||
#[cfg(not(feature = "unstable-blockstore"))]
|
||||
const LOCAL_NETWORK_CAPABILITIES_LEN: usize = 3;
|
||||
|
||||
pub const LOCAL_NETWORK_CAPABILITIES: [Capability; LOCAL_NETWORK_CAPABILITIES_LEN] = [
|
||||
CAP_WILL_RELAY,
|
||||
CAP_WILL_DHT,
|
||||
CAP_WILL_APPMESSAGE,
|
||||
#[cfg(feature = "unstable-blockstore")]
|
||||
CAP_WILL_BLOCKSTORE,
|
||||
];
|
||||
|
||||
pub const MAX_CAPABILITIES: usize = 64;
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Default,
|
||||
@ -21,6 +70,7 @@ pub struct NodeInfo {
|
||||
address_types: AddressTypeSet,
|
||||
envelope_support: Vec<u8>,
|
||||
crypto_support: Vec<CryptoKind>,
|
||||
capabilities: Vec<Capability>,
|
||||
dial_info_detail_list: Vec<DialInfoDetail>,
|
||||
}
|
||||
|
||||
@ -31,6 +81,7 @@ impl NodeInfo {
|
||||
address_types: AddressTypeSet,
|
||||
envelope_support: Vec<u8>,
|
||||
crypto_support: Vec<CryptoKind>,
|
||||
capabilities: Vec<Capability>,
|
||||
dial_info_detail_list: Vec<DialInfoDetail>,
|
||||
) -> Self {
|
||||
Self {
|
||||
@ -39,6 +90,7 @@ impl NodeInfo {
|
||||
address_types,
|
||||
envelope_support,
|
||||
crypto_support,
|
||||
capabilities,
|
||||
dial_info_detail_list,
|
||||
}
|
||||
}
|
||||
@ -58,6 +110,9 @@ impl NodeInfo {
|
||||
pub fn crypto_support(&self) -> &[CryptoKind] {
|
||||
&self.crypto_support
|
||||
}
|
||||
pub fn capabilities(&self) -> &[Capability] {
|
||||
&self.capabilities
|
||||
}
|
||||
pub fn dial_info_detail_list(&self) -> &[DialInfoDetail] {
|
||||
&self.dial_info_detail_list
|
||||
}
|
||||
@ -144,8 +199,17 @@ impl NodeInfo {
|
||||
false
|
||||
}
|
||||
|
||||
fn has_capability(&self, cap: Capability) -> bool {
|
||||
self.capabilities.contains(&cap)
|
||||
}
|
||||
|
||||
/// Can this node assist with signalling? Yes but only if it doesn't require signalling, itself.
|
||||
pub fn can_signal(&self) -> bool {
|
||||
// Has capability?
|
||||
if !self.has_capability(CAP_WILL_SIGNAL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Must be inbound capable
|
||||
if !matches!(self.network_class, NetworkClass::InboundCapable) {
|
||||
return false;
|
||||
@ -161,13 +225,44 @@ impl NodeInfo {
|
||||
|
||||
/// Can this node relay be an inbound relay?
|
||||
pub fn can_inbound_relay(&self) -> bool {
|
||||
// Has capability?
|
||||
if !self.has_capability(CAP_WILL_RELAY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For now this is the same
|
||||
self.can_signal()
|
||||
}
|
||||
|
||||
/// Is this node capable of validating dial info
|
||||
pub fn can_validate_dial_info(&self) -> bool {
|
||||
// Has capability?
|
||||
if !self.has_capability(CAP_WILL_VALIDATE_DIAL_INFO) {
|
||||
return false;
|
||||
}
|
||||
// For now this is the same
|
||||
self.can_signal()
|
||||
}
|
||||
/// Is this node capable of private routing
|
||||
pub fn can_route(&self) -> bool {
|
||||
self.has_capability(CAP_WILL_ROUTE)
|
||||
}
|
||||
/// Is this node capable of dht operations
|
||||
pub fn can_dht(&self) -> bool {
|
||||
self.has_capability(CAP_WILL_DHT)
|
||||
}
|
||||
/// Is this node capable of app_message and app_call
|
||||
pub fn can_appmessage(&self) -> bool {
|
||||
self.has_capability(CAP_WILL_APPMESSAGE)
|
||||
}
|
||||
/// Is this node capable of tunneling
|
||||
#[cfg(feature = "unstable-tunnels")]
|
||||
pub fn can_tunnel(&self) -> bool {
|
||||
self.has_capability(CAP_WILL_TUNNEL)
|
||||
}
|
||||
/// Is this node capable of block storage
|
||||
#[cfg(feature = "unstable-blockstore")]
|
||||
pub fn can_blockstore(&self) -> bool {
|
||||
self.has_capability(CAP_WILL_BLOCKSTORE)
|
||||
}
|
||||
}
|
||||
|
@ -1,47 +1,9 @@
|
||||
use super::*;
|
||||
|
||||
/// RoutingDomain-specific status for each node
|
||||
/// is returned by the StatusA call
|
||||
|
||||
pub type Capability = FourCC;
|
||||
pub const CAP_WILL_ROUTE: Capability = FourCC(*b"ROUT");
|
||||
pub const CAP_WILL_TUNNEL: Capability = FourCC(*b"TUNL");
|
||||
pub const CAP_WILL_SIGNAL: Capability = FourCC(*b"SGNL");
|
||||
pub const CAP_WILL_RELAY: Capability = FourCC(*b"RLAY");
|
||||
pub const CAP_WILL_VALIDATE_DIAL_INFO: Capability = FourCC(*b"DIAL");
|
||||
pub const CAP_WILL_DHT: Capability = FourCC(*b"DHTV");
|
||||
pub const CAP_WILL_APPMESSAGE: Capability = FourCC(*b"APPM");
|
||||
pub const MAX_CAPABILITIES: usize = 64;
|
||||
|
||||
/// PublicInternet RoutingDomain Status
|
||||
#[derive(
|
||||
Clone, Debug, Default, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize,
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct PublicInternetNodeStatus {
|
||||
pub capabilities: Vec<Capability>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone, Debug, Default, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize,
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct LocalNetworkNodeStatus {
|
||||
pub capabilities: Vec<Capability>,
|
||||
}
|
||||
/// Non-nodeinfo status for each node is returned by the StatusA call
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(u8), derive(CheckBytes))]
|
||||
pub enum NodeStatus {
|
||||
PublicInternet(PublicInternetNodeStatus),
|
||||
LocalNetwork(LocalNetworkNodeStatus),
|
||||
}
|
||||
|
||||
impl NodeStatus {
|
||||
pub fn has_capability(&self, cap: Capability) -> bool {
|
||||
match self {
|
||||
NodeStatus::PublicInternet(pi) => pi.capabilities.contains(&cap),
|
||||
NodeStatus::LocalNetwork(ln) => ln.capabilities.contains(&cap),
|
||||
}
|
||||
}
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct NodeStatus {
|
||||
// Reserved for expansion
|
||||
}
|
||||
|
@ -31,6 +31,18 @@ pub fn encode_node_info(
|
||||
s.clone_from_slice(&csvec);
|
||||
}
|
||||
|
||||
let mut cap_builder = builder
|
||||
.reborrow()
|
||||
.init_capabilities(node_info.capabilities().len() as u32);
|
||||
if let Some(s) = cap_builder.as_slice() {
|
||||
let capvec: Vec<u32> = node_info
|
||||
.capabilities()
|
||||
.iter()
|
||||
.map(|x| u32::from_be_bytes(x.0))
|
||||
.collect();
|
||||
|
||||
s.clone_from_slice(&capvec);
|
||||
}
|
||||
let mut didl_builder = builder.reborrow().init_dial_info_detail_list(
|
||||
node_info
|
||||
.dial_info_detail_list()
|
||||
@ -121,6 +133,18 @@ pub fn decode_node_info(reader: &veilid_capnp::node_info::Reader) -> Result<Node
|
||||
return Err(RPCError::protocol("no crypto kinds"));
|
||||
}
|
||||
|
||||
let cap_reader = reader
|
||||
.reborrow()
|
||||
.get_capabilities()
|
||||
.map_err(RPCError::protocol)?;
|
||||
if cap_reader.len() as usize > MAX_CAPABILITIES {
|
||||
return Err(RPCError::protocol("too many capabilities"));
|
||||
}
|
||||
let capabilities = cap_reader
|
||||
.as_slice()
|
||||
.map(|s| s.iter().map(|x| FourCC::from(x.to_be_bytes())).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
let didl_reader = reader
|
||||
.reborrow()
|
||||
.get_dial_info_detail_list()
|
||||
@ -141,6 +165,7 @@ pub fn decode_node_info(reader: &veilid_capnp::node_info::Reader) -> Result<Node
|
||||
address_types,
|
||||
envelope_support,
|
||||
crypto_support,
|
||||
capabilities,
|
||||
dial_info_detail_list,
|
||||
))
|
||||
}
|
||||
|
@ -1,113 +1,14 @@
|
||||
use super::*;
|
||||
|
||||
pub fn encode_public_internet_node_status(
|
||||
public_internet_node_status: &PublicInternetNodeStatus,
|
||||
builder: &mut veilid_capnp::public_internet_node_status::Builder,
|
||||
) -> Result<(), RPCError> {
|
||||
let mut cap_builder = builder
|
||||
.reborrow()
|
||||
.init_capabilities(public_internet_node_status.capabilities.len() as u32);
|
||||
if let Some(s) = cap_builder.as_slice() {
|
||||
let capvec: Vec<u32> = public_internet_node_status
|
||||
.capabilities
|
||||
.iter()
|
||||
.map(|x| u32::from_be_bytes(x.0))
|
||||
.collect();
|
||||
|
||||
s.clone_from_slice(&capvec);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_public_internet_node_status(
|
||||
reader: &veilid_capnp::public_internet_node_status::Reader,
|
||||
) -> Result<PublicInternetNodeStatus, RPCError> {
|
||||
let cap_reader = reader
|
||||
.reborrow()
|
||||
.get_capabilities()
|
||||
.map_err(RPCError::protocol)?;
|
||||
if cap_reader.len() as usize > MAX_CAPABILITIES {
|
||||
return Err(RPCError::protocol("too many capabilities"));
|
||||
}
|
||||
let capabilities = cap_reader
|
||||
.as_slice()
|
||||
.map(|s| s.iter().map(|x| FourCC::from(x.to_be_bytes())).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(PublicInternetNodeStatus { capabilities })
|
||||
}
|
||||
|
||||
pub fn encode_local_network_node_status(
|
||||
local_network_node_status: &LocalNetworkNodeStatus,
|
||||
builder: &mut veilid_capnp::local_network_node_status::Builder,
|
||||
) -> Result<(), RPCError> {
|
||||
let mut cap_builder = builder
|
||||
.reborrow()
|
||||
.init_capabilities(local_network_node_status.capabilities.len() as u32);
|
||||
if let Some(s) = cap_builder.as_slice() {
|
||||
let capvec: Vec<u32> = local_network_node_status
|
||||
.capabilities
|
||||
.iter()
|
||||
.map(|x| u32::from_be_bytes(x.0))
|
||||
.collect();
|
||||
|
||||
s.clone_from_slice(&capvec);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_local_network_node_status(
|
||||
reader: &veilid_capnp::local_network_node_status::Reader,
|
||||
) -> Result<LocalNetworkNodeStatus, RPCError> {
|
||||
let cap_reader = reader
|
||||
.reborrow()
|
||||
.get_capabilities()
|
||||
.map_err(RPCError::protocol)?;
|
||||
if cap_reader.len() as usize > MAX_CAPABILITIES {
|
||||
return Err(RPCError::protocol("too many capabilities"));
|
||||
}
|
||||
let capabilities = cap_reader
|
||||
.as_slice()
|
||||
.map(|s| s.iter().map(|x| FourCC::from(x.to_be_bytes())).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(LocalNetworkNodeStatus { capabilities })
|
||||
}
|
||||
|
||||
pub fn encode_node_status(
|
||||
node_status: &NodeStatus,
|
||||
builder: &mut veilid_capnp::node_status::Builder,
|
||||
_node_status: &NodeStatus,
|
||||
_builder: &mut veilid_capnp::node_status::Builder,
|
||||
) -> Result<(), RPCError> {
|
||||
match node_status {
|
||||
NodeStatus::PublicInternet(ns) => {
|
||||
let mut pi_builder = builder.reborrow().init_public_internet();
|
||||
encode_public_internet_node_status(&ns, &mut pi_builder)
|
||||
}
|
||||
NodeStatus::LocalNetwork(ns) => {
|
||||
let mut ln_builder = builder.reborrow().init_local_network();
|
||||
encode_local_network_node_status(&ns, &mut ln_builder)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_node_status(
|
||||
reader: &veilid_capnp::node_status::Reader,
|
||||
_reader: &veilid_capnp::node_status::Reader,
|
||||
) -> Result<NodeStatus, RPCError> {
|
||||
Ok(
|
||||
match reader
|
||||
.which()
|
||||
.map_err(RPCError::map_internal("invalid node status"))?
|
||||
{
|
||||
veilid_capnp::node_status::PublicInternet(pi) => {
|
||||
let r = pi.map_err(RPCError::protocol)?;
|
||||
let pins = decode_public_internet_node_status(&r)?;
|
||||
NodeStatus::PublicInternet(pins)
|
||||
}
|
||||
veilid_capnp::node_status::LocalNetwork(ln) => {
|
||||
let r = ln.map_err(RPCError::protocol)?;
|
||||
let lnns = decode_local_network_node_status(&r)?;
|
||||
NodeStatus::LocalNetwork(lnns)
|
||||
}
|
||||
},
|
||||
)
|
||||
Ok(NodeStatus {})
|
||||
}
|
||||
|
@ -117,6 +117,13 @@ impl RPCMessageHeader {
|
||||
// RPCMessageHeaderDetail::PrivateRouted(p) => p.direct.peer_noderef.clone(),
|
||||
// }
|
||||
// }
|
||||
pub fn routing_domain(&self) -> RoutingDomain {
|
||||
match &self.detail {
|
||||
RPCMessageHeaderDetail::Direct(d) => d.routing_domain,
|
||||
RPCMessageHeaderDetail::SafetyRouted(s) => s.direct.routing_domain,
|
||||
RPCMessageHeaderDetail::PrivateRouted(p) => p.direct.routing_domain,
|
||||
}
|
||||
}
|
||||
pub fn direct_sender_node_id(&self) -> TypedKey {
|
||||
match &self.detail {
|
||||
RPCMessageHeaderDetail::Direct(d) => {
|
||||
|
@ -54,10 +54,14 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_APPMESSAGE) {
|
||||
return Ok(NetworkResult::service_unavailable("appcall is disabled"));
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_appmessage() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"app call is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,14 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_APPMESSAGE) {
|
||||
return Ok(NetworkResult::service_unavailable("appmessage is disabled"));
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_appmessage() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"app message is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,14 +7,19 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
#[cfg(feature = "unstable-tunnels")]
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_TUNNEL) {
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_tunnel() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"cancel tunnel is disabled",
|
||||
"tunnel is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(RPCError::unimplemented("process_cancel_tunnel_q"))
|
||||
}
|
||||
|
@ -7,14 +7,19 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
#[cfg(feature = "unstable-tunnels")]
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_TUNNEL) {
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_tunnel() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"complete tunnel is disabled",
|
||||
"tunnel is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(RPCError::unimplemented("process_complete_tunnel_q"))
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,17 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
#[cfg(feature = "unstable-blockstore")]
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_BLOCKSTORE) {
|
||||
return Ok(NetworkResult::service_unavailable("find block is disabled"));
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
if let Some(opi) = routing_table.get_own_peer_info(detail.routing_domain) {
|
||||
if !opi.signed_node_info().node_info().can_blockstore() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"block store is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(RPCError::unimplemented("process_find_block_q"))
|
||||
|
@ -163,13 +163,7 @@ impl RPCProcessor {
|
||||
&self,
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_DHT) {
|
||||
return Ok(NetworkResult::service_unavailable("get value is disabled"));
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure this never came over a private route, safety route is okay though
|
||||
match &msg.header.detail {
|
||||
RPCMessageHeaderDetail::Direct(_) | RPCMessageHeaderDetail::SafetyRouted(_) => {}
|
||||
@ -179,7 +173,17 @@ impl RPCProcessor {
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore if disabled
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_dht() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"dht is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get the question
|
||||
let kind = msg.operation.kind().clone();
|
||||
let get_value_q = match kind {
|
||||
|
@ -366,17 +366,16 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities
|
||||
.disable
|
||||
.contains(&CAP_WILL_ROUTE)
|
||||
{
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_route() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"route is disabled",
|
||||
"route is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get header detail, must be direct and not inside a route itself
|
||||
let detail = match msg.header.detail {
|
||||
|
@ -176,10 +176,14 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_DHT) {
|
||||
return Ok(NetworkResult::service_unavailable("set value is disabled"));
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_dht() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"dht is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure this never came over a private route, safety route is okay though
|
||||
|
@ -38,10 +38,14 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_SIGNAL) {
|
||||
return Ok(NetworkResult::service_unavailable("signal is disabled"));
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_signal() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"signal is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,14 +7,19 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
#[cfg(feature = "unstable-tunnels")]
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_TUNNEL) {
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_tunnel() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"start tunnel is disabled",
|
||||
"tunnel is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(RPCError::unimplemented("process_start_tunnel_q"))
|
||||
}
|
||||
}
|
||||
|
@ -133,25 +133,8 @@ impl RPCProcessor {
|
||||
// Ensure the returned node status is the kind for the routing domain we asked for
|
||||
if let Some(target_nr) = opt_target_nr {
|
||||
if let Some(a_node_status) = a_node_status {
|
||||
match routing_domain {
|
||||
RoutingDomain::PublicInternet => {
|
||||
if !matches!(a_node_status, NodeStatus::PublicInternet(_)) {
|
||||
return Ok(NetworkResult::invalid_message(
|
||||
"node status doesn't match PublicInternet routing domain",
|
||||
));
|
||||
}
|
||||
}
|
||||
RoutingDomain::LocalNetwork => {
|
||||
if !matches!(a_node_status, NodeStatus::LocalNetwork(_)) {
|
||||
return Ok(NetworkResult::invalid_message(
|
||||
"node status doesn't match LocalNetwork routing domain",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update latest node status in routing table
|
||||
target_nr.update_node_status(a_node_status.clone());
|
||||
target_nr.update_node_status(routing_domain, a_node_status.clone());
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,27 +219,10 @@ impl RPCProcessor {
|
||||
|
||||
// Ensure the node status from the question is the kind for the routing domain we received the request in
|
||||
if let Some(q_node_status) = q_node_status {
|
||||
match routing_domain {
|
||||
RoutingDomain::PublicInternet => {
|
||||
if !matches!(q_node_status, NodeStatus::PublicInternet(_)) {
|
||||
return Ok(NetworkResult::invalid_message(
|
||||
"node status doesn't match PublicInternet routing domain",
|
||||
));
|
||||
}
|
||||
}
|
||||
RoutingDomain::LocalNetwork => {
|
||||
if !matches!(q_node_status, NodeStatus::LocalNetwork(_)) {
|
||||
return Ok(NetworkResult::invalid_message(
|
||||
"node status doesn't match LocalNetwork routing domain",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update node status for the requesting node to our routing table
|
||||
if let Some(sender_nr) = msg.opt_sender_nr.clone() {
|
||||
// Update latest node status in routing table for the statusq sender
|
||||
sender_nr.update_node_status(q_node_status.clone());
|
||||
sender_nr.update_node_status(routing_domain, q_node_status.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,14 +7,19 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
#[cfg(feature = "unstable-blockstore")]
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_BLOCKSTORE) {
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
if let Some(opi) = routing_table.get_own_peer_info(detail.routing_domain) {
|
||||
if !opi.signed_node_info().node_info().can_blockstore() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"supply block is disabled",
|
||||
"block store is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(RPCError::unimplemented("process_supply_block_q"))
|
||||
}
|
||||
}
|
||||
|
@ -58,19 +58,6 @@ impl RPCProcessor {
|
||||
&self,
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities
|
||||
.disable
|
||||
.contains(&CAP_WILL_VALIDATE_DIAL_INFO)
|
||||
{
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"validate dial info is disabled",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let detail = match msg.header.detail {
|
||||
RPCMessageHeaderDetail::Direct(detail) => detail,
|
||||
RPCMessageHeaderDetail::SafetyRouted(_) | RPCMessageHeaderDetail::PrivateRouted(_) => {
|
||||
@ -80,6 +67,18 @@ impl RPCProcessor {
|
||||
}
|
||||
};
|
||||
|
||||
// Ignore if disabled
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
if let Some(opi) = routing_table.get_own_peer_info(detail.routing_domain) {
|
||||
if !opi.signed_node_info().node_info().can_validate_dial_info() {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"validate dial info is not available",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the statement
|
||||
let (_, _, _, kind) = msg.operation.destructure();
|
||||
let (dial_info, receipt, redirect) = match kind {
|
||||
@ -96,7 +95,6 @@ impl RPCProcessor {
|
||||
// We filter on the -outgoing- protocol capability status not the node's dial info
|
||||
// Use the address type though, to ensure we reach an ipv6 capable node if this is
|
||||
// an ipv6 address
|
||||
let routing_table = self.routing_table();
|
||||
let sender_node_id = TypedKey::new(
|
||||
detail.envelope.get_crypto_kind(),
|
||||
detail.envelope.get_sender_id(),
|
||||
@ -117,11 +115,9 @@ impl RPCProcessor {
|
||||
move |rti: &RoutingTableInner, v: Option<Arc<BucketEntry>>| {
|
||||
let entry = v.unwrap();
|
||||
entry.with(rti, move |_rti, e| {
|
||||
if let Some(status) = &e.node_status(routing_domain) {
|
||||
status.has_capability(CAP_WILL_VALIDATE_DIAL_INFO)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
e.node_info(routing_domain)
|
||||
.map(|ni| ni.can_validate_dial_info())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
},
|
||||
) as RoutingTableEntryFilter;
|
||||
|
@ -7,12 +7,12 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_DHT) {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"value changed is disabled",
|
||||
));
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_dht() {
|
||||
return Ok(NetworkResult::service_unavailable("dht is not available"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(RPCError::unimplemented("process_value_changed"))
|
||||
|
@ -7,15 +7,14 @@ impl RPCProcessor {
|
||||
msg: RPCMessage,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Ignore if disabled
|
||||
let routing_table = self.routing_table();
|
||||
{
|
||||
let c = self.config.get();
|
||||
if c.capabilities.disable.contains(&CAP_WILL_DHT) {
|
||||
return Ok(NetworkResult::service_unavailable(
|
||||
"watch value is disabled",
|
||||
));
|
||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||
if !opi.signed_node_info().node_info().can_dht() {
|
||||
return Ok(NetworkResult::service_unavailable("dht is not available"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(RPCError::unimplemented("process_watch_value_q"))
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ class Capability(StrEnum):
|
||||
CAP_WILL_VALIDATE_DIAL_INFO = "DIAL"
|
||||
CAP_WILL_DHT = "DHTV"
|
||||
CAP_WILL_APPMESSAGE = "APPM"
|
||||
CAP_WILL_BLOCKSTORE = "BLOC"
|
||||
|
||||
|
||||
class Stability(StrEnum):
|
||||
|
Loading…
Reference in New Issue
Block a user