refactor checkpoint

This commit is contained in:
John Smith 2022-09-03 13:57:25 -04:00
parent 9966d25672
commit e0a5b1bd69
30 changed files with 1274 additions and 838 deletions

View File

@ -3,5 +3,4 @@ core:
network: network:
dht: dht:
min_peer_count: 1 min_peer_count: 1
enable_local_peer_scope: true
bootstrap: [] bootstrap: []

View File

@ -175,10 +175,6 @@ struct ValueData {
# Operations # Operations
############################## ##############################
struct OperationStatusQ {
nodeStatus @0 :NodeStatus; # node status update about the statusq sender
}
enum NetworkClass { enum NetworkClass {
inboundCapable @0; # I = Inbound capable without relay, may require signal inboundCapable @0; # I = Inbound capable without relay, may require signal
outboundOnly @1; # O = Outbound only, inbound relay required except with reverse connect signal outboundOnly @1; # O = Outbound only, inbound relay required except with reverse connect signal
@ -199,7 +195,7 @@ struct DialInfoDetail {
class @1 :DialInfoClass; class @1 :DialInfoClass;
} }
struct NodeStatus { struct PublicInternetNodeStatus {
willRoute @0 :Bool; willRoute @0 :Bool;
willTunnel @1 :Bool; willTunnel @1 :Bool;
willSignal @2 :Bool; willSignal @2 :Bool;
@ -207,6 +203,18 @@ struct NodeStatus {
willValidateDialInfo @4 :Bool; willValidateDialInfo @4 :Bool;
} }
struct LocalNetworkNodeStatus {
willRelay @0 :Bool;
willValidateDialInfo @1 :Bool;
}
struct NodeStatus {
union {
publicInternet @0 :PublicInternetNodeStatus;
localNetwork @1 :LocalNetworkNodeStatus;
}
}
struct ProtocolTypeSet { struct ProtocolTypeSet {
udp @0 :Bool; udp @0 :Bool;
tcp @1 :Bool; tcp @1 :Bool;
@ -239,6 +247,21 @@ struct SenderInfo {
socketAddress @0 :SocketAddress; # socket address was available for peer socketAddress @0 :SocketAddress; # socket address was available for peer
} }
struct PeerInfo {
nodeId @0 :NodeID; # node id for 'closer peer'
signedNodeInfo @1 :SignedNodeInfo; # signed node info for 'closer peer'
}
struct RoutedOperation {
signatures @0 :List(Signature); # signatures from nodes that have handled the private route
nonce @1 :Nonce; # nonce Xmsg
data @2 :Data; # Operation encrypted with ENC(Xmsg,DH(PKapr,SKbsr))
}
struct OperationStatusQ {
nodeStatus @0 :NodeStatus; # node status update about the statusq sender
}
struct OperationStatusA { struct OperationStatusA {
nodeStatus @0 :NodeStatus; # returned node status nodeStatus @0 :NodeStatus; # returned node status
senderInfo @1 :SenderInfo; # info about StatusQ sender from the perspective of the replier senderInfo @1 :SenderInfo; # info about StatusQ sender from the perspective of the replier
@ -258,21 +281,10 @@ struct OperationFindNodeQ {
nodeId @0 :NodeID; # node id to locate nodeId @0 :NodeID; # node id to locate
} }
struct PeerInfo {
nodeId @0 :NodeID; # node id for 'closer peer'
signedNodeInfo @1 :SignedNodeInfo; # signed node info for 'closer peer'
}
struct OperationFindNodeA { struct OperationFindNodeA {
peers @0 :List(PeerInfo); # returned 'closer peer' information peers @0 :List(PeerInfo); # returned 'closer peer' information
} }
struct RoutedOperation {
signatures @0 :List(Signature); # signatures from nodes that have handled the private route
nonce @1 :Nonce; # nonce Xmsg
data @2 :Data; # Operation encrypted with ENC(Xmsg,DH(PKapr,SKbsr))
}
struct OperationRoute { struct OperationRoute {
safetyRoute @0 :SafetyRoute; # Where this should go safetyRoute @0 :SafetyRoute; # Where this should go
operation @1 :RoutedOperation; # The operation to be routed operation @1 :RoutedOperation; # The operation to be routed
@ -419,26 +431,25 @@ struct OperationCancelTunnelA {
# Things that want an answer # Things that want an answer
struct Question { struct Question {
respondTo :union { respondTo :union {
sender @0 :Void; # sender without node info sender @0 :Void; # sender
senderWithInfo @1 :SignedNodeInfo; # some envelope-sender signed node info to be used for reply privateRoute @1 :PrivateRoute; # embedded private route to be used for reply
privateRoute @2 :PrivateRoute; # embedded private route to be used for reply
} }
detail :union { detail :union {
# Direct operations # Direct operations
statusQ @3 :OperationStatusQ; statusQ @2 :OperationStatusQ;
findNodeQ @4 :OperationFindNodeQ; findNodeQ @3 :OperationFindNodeQ;
# Routable operations # Routable operations
getValueQ @5 :OperationGetValueQ; getValueQ @4 :OperationGetValueQ;
setValueQ @6 :OperationSetValueQ; setValueQ @5 :OperationSetValueQ;
watchValueQ @7 :OperationWatchValueQ; watchValueQ @6 :OperationWatchValueQ;
supplyBlockQ @8 :OperationSupplyBlockQ; supplyBlockQ @7 :OperationSupplyBlockQ;
findBlockQ @9 :OperationFindBlockQ; findBlockQ @8 :OperationFindBlockQ;
# Tunnel operations # Tunnel operations
startTunnelQ @10 :OperationStartTunnelQ; startTunnelQ @9 :OperationStartTunnelQ;
completeTunnelQ @11 :OperationCompleteTunnelQ; completeTunnelQ @10 :OperationCompleteTunnelQ;
cancelTunnelQ @12 :OperationCancelTunnelQ; cancelTunnelQ @11 :OperationCancelTunnelQ;
} }
} }
@ -480,10 +491,10 @@ struct Answer {
struct Operation { struct Operation {
opId @0 :UInt64; # Random RPC ID. Must be random to foil reply forgery attacks. opId @0 :UInt64; # Random RPC ID. Must be random to foil reply forgery attacks.
senderInfo @1 :SignedNodeInfo; # (optional) SignedNodeInfo for the sender to be cached by the receiver.
kind :union { kind :union {
question @1 :Question; question @2 :Question;
statement @2 :Statement; statement @3 :Statement;
answer @3 :Answer; answer @4 :Answer;
} }
} }

View File

@ -552,33 +552,29 @@ impl NetworkManager {
// Run the rolling transfers task // Run the rolling transfers task
self.unlocked_inner.rolling_transfers_task.tick().await?; self.unlocked_inner.rolling_transfers_task.tick().await?;
// Process global peer scope ticks // Run the relay management task
// These only make sense when connected to the actual internet and not just the local network self.unlocked_inner.relay_management_task.tick().await?;
// Must have at least one outbound protocol enabled, and one global peer scope address family enabled
let global_peer_scope_enabled =
!protocol_config.outbound.is_empty() && !protocol_config.family_global.is_empty();
if global_peer_scope_enabled {
// Run the relay management task
self.unlocked_inner.relay_management_task.tick().await?;
// If routing table has no live entries, then add the bootstrap nodes to it // See how many live PublicInternet entries we have
let live_entry_count = routing_table.get_entry_count(BucketEntryState::Unreliable); let live_public_internet_entry_count = routing_table.get_entry_count(
if live_entry_count == 0 { RoutingTableSet::only(RoutingTable::PublicInternet),
self.unlocked_inner.bootstrap_task.tick().await?; BucketEntryState::Unreliable,
} );
let min_peer_count = {
// If we still don't have enough peers, find nodes until we do let c = self.config.get();
let min_peer_count = { c.network.dht.min_peer_count as usize
let c = self.config.get(); };
c.network.dht.min_peer_count as usize // If none, then add the bootstrap nodes to it
}; if live_public_internet_entry_count == 0 {
if live_entry_count < min_peer_count { self.unlocked_inner.bootstrap_task.tick().await?;
self.unlocked_inner.peer_minimum_refresh_task.tick().await?;
}
// Ping validate some nodes to groom the table
self.unlocked_inner.ping_validator_task.tick().await?;
} }
// If we still don't have enough peers, find nodes until we do
else if live_public_internet_entry_count < min_peer_count {
self.unlocked_inner.peer_minimum_refresh_task.tick().await?;
}
// Ping validate some nodes to groom the table
self.unlocked_inner.ping_validator_task.tick().await?;
// Run the routing table tick // Run the routing table tick
routing_table.tick().await?; routing_table.tick().await?;
@ -605,21 +601,18 @@ impl NetworkManager {
} }
// Get our node's capabilities // Get our node's capabilities
pub fn generate_node_status(&self) -> NodeStatus { fn generate_public_internet_node_status(&self) -> PublicInternetNodeStatus {
let peer_info = self let node_info = self
.routing_table() .routing_table()
.get_own_peer_info(RoutingDomain::PublicInternet); .get_own_node_info(RoutingDomain::PublicInternet);
let will_route = peer_info.signed_node_info.node_info.can_inbound_relay(); // xxx: eventually this may have more criteria added let will_route = node_info.can_inbound_relay(); // xxx: eventually this may have more criteria added
let will_tunnel = peer_info.signed_node_info.node_info.can_inbound_relay(); // xxx: we may want to restrict by battery life and network bandwidth at some point let will_tunnel = node_info.can_inbound_relay(); // xxx: we may want to restrict by battery life and network bandwidth at some point
let will_signal = peer_info.signed_node_info.node_info.can_signal(); let will_signal = node_info.can_signal();
let will_relay = peer_info.signed_node_info.node_info.can_inbound_relay(); let will_relay = node_info.can_inbound_relay();
let will_validate_dial_info = peer_info let will_validate_dial_info = node_info.can_validate_dial_info();
.signed_node_info
.node_info
.can_validate_dial_info();
NodeStatus { PublicInternetNodeStatus {
will_route, will_route,
will_tunnel, will_tunnel,
will_signal, will_signal,
@ -627,6 +620,30 @@ impl NetworkManager {
will_validate_dial_info, will_validate_dial_info,
} }
} }
fn generate_local_network_node_status(&self) -> LocalNetworkNodeStatus {
let node_info = self
.routing_table()
.get_own_node_info(RoutingDomain::LocalNetwork);
let will_relay = node_info.can_inbound_relay();
let will_validate_dial_info = node_info.can_validate_dial_info();
LocalNetworkNodeStatus {
will_relay,
will_validate_dial_info,
}
}
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())
}
}
}
// Return what protocols we have enabled // Return what protocols we have enabled
pub fn get_protocol_config(&self) -> ProtocolConfig { pub fn get_protocol_config(&self) -> ProtocolConfig {
@ -650,6 +667,12 @@ impl NetworkManager {
.clone(), .clone(),
} }
} }
pub fn get_inbound_node_ref_filter(&self, routing_domain: RoutingDomain) -> NodeRefFilter {
let dif = self.get_inbound_dial_info_filter(routing_domain);
NodeRefFilter::new()
.with_routing_domain(routing_domain)
.with_dial_info_filter(dif)
}
// Return a dial info filter for what we can send out // Return a dial info filter for what we can send out
pub fn get_outbound_dial_info_filter(&self, routing_domain: RoutingDomain) -> DialInfoFilter { pub fn get_outbound_dial_info_filter(&self, routing_domain: RoutingDomain) -> DialInfoFilter {
@ -667,6 +690,12 @@ impl NetworkManager {
.clone(), .clone(),
} }
} }
pub fn get_outbound_node_ref_filter(&self, routing_domain: RoutingDomain) -> NodeRefFilter {
let dif = self.get_outbound_dial_info_filter(routing_domain);
NodeRefFilter::new()
.with_routing_domain(routing_domain)
.with_dial_info_filter(dif)
}
// Generates a multi-shot/normal receipt // Generates a multi-shot/normal receipt
#[instrument(level = "trace", skip(self, extra_data, callback), err)] #[instrument(level = "trace", skip(self, extra_data, callback), err)]
@ -949,12 +978,11 @@ impl NetworkManager {
#[instrument(level = "trace", skip(self), ret)] #[instrument(level = "trace", skip(self), ret)]
fn get_contact_method_public(&self, target_node_ref: NodeRef) -> ContactMethod { fn get_contact_method_public(&self, target_node_ref: NodeRef) -> ContactMethod {
// Scope noderef down to protocols we can do outbound // Scope noderef down to protocols we can do outbound
let public_outbound_dif = self.get_outbound_dial_info_filter(RoutingDomain::PublicInternet); let public_outbound_nrf = self.get_outbound_node_ref_filter(RoutingDomain::PublicInternet);
let target_node_ref = target_node_ref.filtered_clone(public_outbound_dif.clone()); let target_node_ref = target_node_ref.filtered_clone(public_outbound_nrf.clone());
// Get the best match internet dial info if we have it // Get the best match internet dial info if we have it
let opt_target_public_did = let opt_target_public_did = target_node_ref.first_filtered_dial_info_detail();
target_node_ref.first_filtered_dial_info_detail(Some(RoutingDomain::PublicInternet));
if let Some(target_public_did) = opt_target_public_did { if let Some(target_public_did) = opt_target_public_did {
// Do we need to signal before going inbound? // Do we need to signal before going inbound?
if !target_public_did.class.requires_signal() { if !target_public_did.class.requires_signal() {
@ -966,12 +994,9 @@ impl NetworkManager {
// Note that .relay() never returns our own node. We can't relay to ourselves. // Note that .relay() never returns our own node. We can't relay to ourselves.
if let Some(inbound_relay_nr) = target_node_ref.relay(RoutingDomain::PublicInternet) { if let Some(inbound_relay_nr) = target_node_ref.relay(RoutingDomain::PublicInternet) {
// Scope down to protocols we can do outbound // Scope down to protocols we can do outbound
let inbound_relay_nr = inbound_relay_nr.filtered_clone(public_outbound_dif.clone()); let inbound_relay_nr = inbound_relay_nr.filtered_clone(public_outbound_nrf.clone());
// Can we reach the inbound relay? // Can we reach the inbound relay?
if inbound_relay_nr if inbound_relay_nr.first_filtered_dial_info_detail().is_some() {
.first_filtered_dial_info_detail(Some(RoutingDomain::PublicInternet))
.is_some()
{
// Can we receive anything inbound ever? // Can we receive anything inbound ever?
let our_network_class = self let our_network_class = self
.get_network_class(RoutingDomain::PublicInternet) .get_network_class(RoutingDomain::PublicInternet)
@ -985,11 +1010,11 @@ impl NetworkManager {
let reverse_dif = self let reverse_dif = self
.get_inbound_dial_info_filter(RoutingDomain::PublicInternet) .get_inbound_dial_info_filter(RoutingDomain::PublicInternet)
.filtered( .filtered(
target_node_ref &target_node_ref
.node_info_outbound_filter(RoutingDomain::PublicInternet), .node_info_outbound_filter(RoutingDomain::PublicInternet),
); );
if let Some(reverse_did) = routing_table.first_filtered_dial_info_detail( if let Some(reverse_did) = routing_table.first_filtered_dial_info_detail(
Some(RoutingDomain::PublicInternet), RoutingDomainSet::only(RoutingDomain::PublicInternet),
&reverse_dif, &reverse_dif,
) { ) {
// Ensure we aren't on the same public IP address (no hairpin nat) // Ensure we aren't on the same public IP address (no hairpin nat)
@ -1010,16 +1035,16 @@ impl NetworkManager {
// Does the target have a direct udp dialinfo we can reach? // Does the target have a direct udp dialinfo we can reach?
let udp_target_nr = target_node_ref.filtered_clone( let udp_target_nr = target_node_ref.filtered_clone(
DialInfoFilter::global().with_protocol_type(ProtocolType::UDP), NodeRefFilter::new().with_protocol_type(ProtocolType::UDP),
); );
if let Some(target_udp_dialinfo_detail) = udp_target_nr if let Some(target_udp_dialinfo_detail) =
.first_filtered_dial_info_detail(Some(RoutingDomain::PublicInternet)) udp_target_nr.first_filtered_dial_info_detail()
{ {
// Does the self node have a direct udp dialinfo the target can reach? // Does the self node have a direct udp dialinfo the target can reach?
let inbound_udp_dif = self let inbound_udp_dif = self
.get_inbound_dial_info_filter(RoutingDomain::PublicInternet) .get_inbound_dial_info_filter(RoutingDomain::PublicInternet)
.filtered( .filtered(
target_node_ref &target_node_ref
.node_info_outbound_filter(RoutingDomain::PublicInternet), .node_info_outbound_filter(RoutingDomain::PublicInternet),
) )
.filtered( .filtered(
@ -1027,7 +1052,7 @@ impl NetworkManager {
); );
if let Some(self_udp_dialinfo_detail) = routing_table if let Some(self_udp_dialinfo_detail) = routing_table
.first_filtered_dial_info_detail( .first_filtered_dial_info_detail(
Some(RoutingDomain::PublicInternet), RoutingDomainSet::only(RoutingDomain::PublicInternet),
&inbound_udp_dif, &inbound_udp_dif,
) )
{ {
@ -1056,7 +1081,7 @@ impl NetworkManager {
{ {
// Can we reach the full relay? // Can we reach the full relay?
if target_inbound_relay_nr if target_inbound_relay_nr
.first_filtered_dial_info_detail(Some(RoutingDomain::PublicInternet)) .first_filtered_dial_info_detail()
.is_some() .is_some()
{ {
return ContactMethod::InboundRelay(target_inbound_relay_nr); return ContactMethod::InboundRelay(target_inbound_relay_nr);
@ -1078,15 +1103,13 @@ impl NetworkManager {
fn get_contact_method_local(&self, target_node_ref: NodeRef) -> ContactMethod { fn get_contact_method_local(&self, target_node_ref: NodeRef) -> ContactMethod {
// Scope noderef down to protocols we can do outbound // Scope noderef down to protocols we can do outbound
let local_outbound_dif = self.get_outbound_dial_info_filter(RoutingDomain::LocalNetwork); let local_outbound_dif = self.get_outbound_dial_info_filter(RoutingDomain::LocalNetwork);
let target_node_ref = target_node_ref.filtered_clone(local_outbound_dif); let target_node_ref = target_node_ref.filtered_clone(NodeRefFilter::local_outbound_dif);
// Get the best matching local direct dial info if we have it // Get the best matching local direct dial info if we have it
// ygjghhtiygiukuymyg
if target_node_ref.is_filter_dead() { if target_node_ref.is_filter_dead() {
return ContactMethod::Unreachable; return ContactMethod::Unreachable;
} }
let opt_target_local_did = let opt_target_local_did = target_node_ref.first_filtered_dial_info_detail();
target_node_ref.first_filtered_dial_info_detail(Some(RoutingDomain::LocalNetwork));
if let Some(target_local_did) = opt_target_local_did { if let Some(target_local_did) = opt_target_local_did {
return ContactMethod::Direct(target_local_did.dial_info); return ContactMethod::Direct(target_local_did.dial_info);
} }
@ -1096,21 +1119,18 @@ impl NetworkManager {
// Figure out how to reach a node // Figure out how to reach a node
#[instrument(level = "trace", skip(self), ret)] #[instrument(level = "trace", skip(self), ret)]
pub(crate) fn get_contact_method(&self, target_node_ref: NodeRef) -> ContactMethod { pub(crate) fn get_contact_method(&self, target_node_ref: NodeRef) -> ContactMethod {
// Try local first let routing_domain = match target_node_ref.best_routing_domain() {
let out = self.get_contact_method_local(target_node_ref.clone()); Some(rd) => rd,
if !matches!(out, ContactMethod::Unreachable) { None => {
return out; log_net!("no routing domain for node {:?}", target_node_ref);
} return ContactMethod::Unreachable;
}
};
// Try public next match routing_domain {
let out = self.get_contact_method_public(target_node_ref.clone()); RoutingDomain::LocalNetwork => self.get_contact_method_local(target_node_ref),
if !matches!(out, ContactMethod::Unreachable) { RoutingDomain::PublicInternet => self.get_contact_method_public(target_node_ref),
return out;
} }
// Otherwise, we can't reach this node
log_net!("unable to reach node {:?}", target_node_ref);
ContactMethod::Unreachable
} }
// Send a reverse connection signal and wait for the return receipt over it // Send a reverse connection signal and wait for the return receipt over it
@ -1461,6 +1481,18 @@ impl NetworkManager {
return Ok(false); return Ok(false);
} }
// Get the routing domain for this data
let routing_domain = match self
.routing_table()
.routing_domain_for_address(connection_descriptor.remote().address())
{
Some(rd) => rd,
None => {
log_net!(debug "no routing domain for envelope received from {:?}", connection_descriptor);
return Ok(false);
}
};
// Is this a direct bootstrap request instead of an envelope? // Is this a direct bootstrap request instead of an envelope?
if data[0..4] == *BOOT_MAGIC { if data[0..4] == *BOOT_MAGIC {
network_result_value_or_log!(debug self.handle_boot_request(connection_descriptor).await? => {}); network_result_value_or_log!(debug self.handle_boot_request(connection_descriptor).await? => {});
@ -1588,7 +1620,13 @@ impl NetworkManager {
// xxx: deal with spoofing and flooding here? // xxx: deal with spoofing and flooding here?
// Pass message to RPC system // Pass message to RPC system
rpc.enqueue_message(envelope, body, source_noderef, connection_descriptor)?; rpc.enqueue_message(
envelope,
body,
source_noderef,
connection_descriptor,
routing_domain,
)?;
// Inform caller that we dealt with the envelope locally // Inform caller that we dealt with the envelope locally
Ok(true) Ok(true)
@ -1669,7 +1707,7 @@ impl NetworkManager {
// Determine if a local IP address has changed // Determine if a local IP address has changed
// this means we should restart the low level network and and recreate all of our dial info // this means we should restart the low level network and and recreate all of our dial info
// Wait until we have received confirmation from N different peers // Wait until we have received confirmation from N different peers
pub fn report_local_socket_address( pub fn report_local_network_socket_address(
&self, &self,
_socket_address: SocketAddress, _socket_address: SocketAddress,
_connection_descriptor: ConnectionDescriptor, _connection_descriptor: ConnectionDescriptor,
@ -1681,7 +1719,7 @@ impl NetworkManager {
// Determine if a global IP address has changed // Determine if a global IP address has changed
// this means we should recreate our public dial info if it is not static and rediscover it // this means we should recreate our public dial info if it is not static and rediscover it
// Wait until we have received confirmation from N different peers // Wait until we have received confirmation from N different peers
pub fn report_global_socket_address( pub fn report_public_internet_socket_address(
&self, &self,
socket_address: SocketAddress, // the socket address as seen by the remote peer socket_address: SocketAddress, // the socket address as seen by the remote peer
connection_descriptor: ConnectionDescriptor, // the connection descriptor used connection_descriptor: ConnectionDescriptor, // the connection descriptor used

View File

@ -603,6 +603,29 @@ impl Network {
// initialize interfaces // initialize interfaces
self.unlocked_inner.interfaces.refresh().await?; self.unlocked_inner.interfaces.refresh().await?;
// build the set of networks we should consider for the 'LocalNetwork' routing domain
let mut local_networks: HashSet<(IpAddr, IpAddr)> = HashSet::new();
self.unlocked_inner
.interfaces
.with_interfaces(|interfaces| {
for (name, intf) in interfaces {
// Skip networks that we should never encounter
if intf.is_loopback() || !intf.is_running() {
return;
}
// Add network to local networks table
for addr in intf.addrs {
let netmask = addr.if_addr().netmask();
let network_ip = ipaddr_apply_netmask(addr.if_addr().ip(), netmask);
local_networks.insert((network_ip, netmask));
}
}
});
let local_networks: Vec<(IpAddr, IpAddr)> = local_networks.into_iter().collect();
self.unlocked_inner
.routing_table
.configure_local_network_routing_domain(local_networks);
// determine if we have ipv4/ipv6 addresses // determine if we have ipv4/ipv6 addresses
{ {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();

View File

@ -367,13 +367,12 @@ xxx write routing table sieve for routing domain from dialinfo and local network
pub(super) async fn start_ws_listeners(&self) -> EyreResult<()> { pub(super) async fn start_ws_listeners(&self) -> EyreResult<()> {
trace!("starting ws listeners"); trace!("starting ws listeners");
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let (listen_address, url, path, enable_local_peer_scope, detect_address_changes) = { let (listen_address, url, path, detect_address_changes) = {
let c = self.config.get(); let c = self.config.get();
( (
c.network.protocol.ws.listen_address.clone(), c.network.protocol.ws.listen_address.clone(),
c.network.protocol.ws.url.clone(), c.network.protocol.ws.url.clone(),
c.network.protocol.ws.path.clone(), c.network.protocol.ws.path.clone(),
c.network.enable_local_peer_scope,
c.network.detect_address_changes, c.network.detect_address_changes,
) )
}; };
@ -586,12 +585,11 @@ xxx write routing table sieve for routing domain from dialinfo and local network
trace!("starting tcp listeners"); trace!("starting tcp listeners");
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let (listen_address, public_address, enable_local_peer_scope, detect_address_changes) = { let (listen_address, public_address, detect_address_changes) = {
let c = self.config.get(); let c = self.config.get();
( (
c.network.protocol.tcp.listen_address.clone(), c.network.protocol.tcp.listen_address.clone(),
c.network.protocol.tcp.public_address.clone(), c.network.protocol.tcp.public_address.clone(),
c.network.enable_local_peer_scope,
c.network.detect_address_changes, c.network.detect_address_changes,
) )
}; };

View File

@ -197,7 +197,11 @@ impl NetworkManager {
let routing_table = routing_table.clone(); let routing_table = routing_table.clone();
unord.push( unord.push(
// lets ask bootstrap to find ourselves now // lets ask bootstrap to find ourselves now
async move { routing_table.reverse_find_node(nr, true).await }, async move {
routing_table
.reverse_find_node(RoutingDomain::PublicInternet, nr, true)
.await
},
); );
} }
} }
@ -299,7 +303,9 @@ impl NetworkManager {
unord.push(async move { unord.push(async move {
// Need VALID signed peer info, so ask bootstrap to find_node of itself // Need VALID signed peer info, so ask bootstrap to find_node of itself
// which will ensure it has the bootstrap's signed peer info as part of the response // which will ensure it has the bootstrap's signed peer info as part of the response
let _ = routing_table.find_target(nr.clone()).await; let _ = routing_table
.find_target(RoutingDomain::PublicInternet, nr.clone())
.await;
// Ensure we got the signed peer info // Ensure we got the signed peer info
if !nr.has_valid_signed_node_info(Some(RoutingDomain::PublicInternet)) { if !nr.has_valid_signed_node_info(Some(RoutingDomain::PublicInternet)) {
@ -310,7 +316,9 @@ impl NetworkManager {
// If this node info is invalid, it will time out after being unpingable // If this node info is invalid, it will time out after being unpingable
} else { } else {
// otherwise this bootstrap is valid, lets ask it to find ourselves now // otherwise this bootstrap is valid, lets ask it to find ourselves now
routing_table.reverse_find_node(nr, true).await routing_table
.reverse_find_node(RoutingDomain::PublicInternet, nr, true)
.await
} }
}); });
} }
@ -324,33 +332,35 @@ impl NetworkManager {
// Ping each node in the routing table if they need to be pinged // Ping each node in the routing table if they need to be pinged
// to determine their reliability // to determine their reliability
#[instrument(level = "trace", skip(self), err)] #[instrument(level = "trace", skip(self), err)]
pub(super) async fn ping_validator_task_routine( fn ping_validator_public_internet(
self, &self,
stop_token: StopToken,
_last_ts: u64,
cur_ts: u64, cur_ts: u64,
unord: &mut FuturesUnordered,
) -> EyreResult<()> { ) -> EyreResult<()> {
let rpc = self.rpc_processor(); let rpc = self.rpc_processor();
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let mut unord = FuturesUnordered::new(); // Get all nodes needing pings in the PublicInternet routing domain
let node_refs = routing_table.get_nodes_needing_ping(RoutingDomain::PublicInternet, cur_ts);
let node_refs = routing_table.get_nodes_needing_ping(cur_ts); // Look up any NAT mappings we may need to try to preserve with keepalives
let mut mapped_port_info = routing_table.get_mapped_port_info(); let mut mapped_port_info = routing_table.get_mapped_port_info();
let opt_public_internet_relay_nr = routing_table.relay_node(RoutingDomain::PublicInternet);
let opt_public_internet_relay_id = opt_public_internet_relay_nr.map(|nr| nr.node_id());
// let opt_local_network_relay_nr = routing_table.relay_node(RoutingDomain::LocalNetwork);
// let opt_local_network_relay_id = opt_local_network_relay_nr.map(|nr| nr.node_id());
// Public Internet Routing Domain // Get the PublicInternet relay if we are using one
let opt_relay_nr = routing_table.relay_node(RoutingDomain::PublicInternet);
let opt_relay_id = opt_relay_nr.map(|nr| nr.node_id());
// Get our publicinternet dial info
let dids = routing_table.all_filtered_dial_info_details( let dids = routing_table.all_filtered_dial_info_details(
Some(RoutingDomain::PublicInternet), RoutingDomainSet::only(RoutingDomain::PublicInternet),
&DialInfoFilter::global(), &DialInfoFilter::all(),
); );
// For all nodes needing pings, figure out how many and over what protocols
for nr in node_refs { for nr in node_refs {
let rpc = rpc.clone(); // If this is a relay, let's check for NAT keepalives
if Some(nr.node_id()) == opt_public_internet_relay_id { let mut did_pings = false;
if Some(nr.node_id()) == opt_relay_id {
// Relay nodes get pinged over all protocols we have inbound dialinfo for // Relay nodes get pinged over all protocols we have inbound dialinfo for
// This is so we can preserve the inbound NAT mappings at our router // This is so we can preserve the inbound NAT mappings at our router
for did in &dids { for did in &dids {
@ -370,19 +380,84 @@ impl NetworkManager {
}; };
if needs_ping { if needs_ping {
let rpc = rpc.clone(); let rpc = rpc.clone();
let dif = did.dial_info.make_filter(true); let dif = did.dial_info.make_filter();
let nr_filtered = nr.filtered_clone(dif); let nr_filtered = nr.filtered_clone(dif);
log_net!("--> Keepalive ping to {:?}", nr_filtered); log_net!("--> Keepalive ping to {:?}", nr_filtered);
unord.push(async move { rpc.rpc_call_status(nr_filtered).await }.boxed()); unord.push(
async move {
rpc.rpc_call_status(Some(routing_domain), nr_filtered).await
}
.boxed(),
);
did_pings = true;
} }
} }
} else { }
// Just do a single ping with the best protocol for all the other nodes // Just do a single ping with the best protocol for all the other nodes,
unord.push(async move { rpc.rpc_call_status(nr).await }.boxed()); // ensuring that we at least ping a relay with -something- even if we didnt have
// any mapped ports to preserve
if !did_pings {
let rpc = rpc.clone();
unord.push(
async move { rpc.rpc_call_status(Some(routing_domain), nr).await }.boxed(),
);
} }
} }
// Wait for futures to complete Ok(())
}
// Ping each node in the LocalNetwork routing domain if they
// need to be pinged to determine their reliability
#[instrument(level = "trace", skip(self), err)]
fn ping_validator_local_network(
&self,
cur_ts: u64,
unord: &mut FuturesUnordered,
) -> EyreResult<()> {
let rpc = self.rpc_processor();
let routing_table = self.routing_table();
// Get all nodes needing pings in the LocalNetwork routing domain
let node_refs = routing_table.get_nodes_needing_ping(RoutingDomain::LocalNetwork, cur_ts);
// Get our LocalNetwork dial info
let dids = routing_table.all_filtered_dial_info_details(
RoutingDomainSet::only(RoutingDomain::LocalNetwork),
&DialInfoFilter::all(),
);
// For all nodes needing pings, figure out how many and over what protocols
for nr in node_refs {
let rpc = rpc.clone();
// Just do a single ping with the best protocol for all the nodes
unord.push(async move { rpc.rpc_call_status(Some(routing_domain), nr).await }.boxed());
}
Ok(())
}
// Ping each node in the routing table if they need to be pinged
// to determine their reliability
#[instrument(level = "trace", skip(self), err)]
pub(super) async fn ping_validator_task_routine(
self,
stop_token: StopToken,
_last_ts: u64,
cur_ts: u64,
) -> EyreResult<()> {
let rpc = self.rpc_processor();
let routing_table = self.routing_table();
let mut unord = FuturesUnordered::new();
// PublicInternet
self.ping_validator_public_internet(cur_ts, &mut unord)?;
// LocalNetwork
self.ping_validator_local_network(cur_ts, &mut unord)?;
// Wait for ping futures to complete in parallel
while let Ok(Some(_)) = unord.next().timeout_at(stop_token.clone()).await {} while let Ok(Some(_)) = unord.next().timeout_at(stop_token.clone()).await {}
Ok(()) Ok(())
@ -390,24 +465,38 @@ impl NetworkManager {
// Ask our remaining peers to give us more peers before we go // Ask our remaining peers to give us more peers before we go
// back to the bootstrap servers to keep us from bothering them too much // back to the bootstrap servers to keep us from bothering them too much
// This only adds PublicInternet routing domain peers. The discovery
// mechanism for LocalNetwork suffices for locating all the local network
// peers that are available. This, however, may query other LocalNetwork
// nodes for their PublicInternet peers, which is a very fast way to get
// a new node online.
#[instrument(level = "trace", skip(self), err)] #[instrument(level = "trace", skip(self), err)]
pub(super) async fn peer_minimum_refresh_task_routine( pub(super) async fn peer_minimum_refresh_task_routine(
self, self,
stop_token: StopToken, stop_token: StopToken,
) -> EyreResult<()> { ) -> EyreResult<()> {
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let cur_ts = intf::get_timestamp(); let mut unord = FuturesOrdered::new();
let min_peer_count = {
let c = self.config.get();
c.network.dht.min_peer_count as usize
};
// get list of all peers we know about, even the unreliable ones, and ask them to find nodes close to our node too // For the PublicInternet routing domain, get list of all peers we know about
let noderefs = routing_table.get_all_nodes(cur_ts); // even the unreliable ones, and ask them to find nodes close to our node too
let noderefs = routing_table.find_fastest_nodes(
// do peer minimum search concurrently min_peer_count,
let mut unord = FuturesUnordered::new(); None,
|k: DHTKey, v: Option<Arc<BucketEntry>>| {
NodeRef::new(self.clone(), k, v.unwrap().clone(), None)
},
);
for nr in noderefs { for nr in noderefs {
log_net!("--- peer minimum search with {:?}", nr);
let routing_table = routing_table.clone(); let routing_table = routing_table.clone();
unord.push(async move { routing_table.reverse_find_node(nr, false).await }); unord.push(async move { routing_table.reverse_find_node(nr, false).await });
} }
// do peer minimum search in order from fastest to slowest
while let Ok(Some(_)) = unord.next().timeout_at(stop_token.clone()).await {} while let Ok(Some(_)) = unord.next().timeout_at(stop_token.clone()).await {}
Ok(()) Ok(())

View File

@ -39,7 +39,7 @@ pub enum BucketEntryState {
} }
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
struct LastConnectionKey(ProtocolType, AddressType); struct LastConnectionKey(RoutingDomain, ProtocolType, AddressType);
/// Bucket entry information specific to the LocalNetwork RoutingDomain /// Bucket entry information specific to the LocalNetwork RoutingDomain
#[derive(Debug)] #[derive(Debug)]
@ -136,10 +136,18 @@ impl BucketEntryInner {
move |e1, e2| Self::cmp_fastest_reliable(cur_ts, e1, e2) move |e1, e2| Self::cmp_fastest_reliable(cur_ts, e1, e2)
} }
pub fn clear_signed_node_info(&mut self, routing_domain: RoutingDomain) {
// Get the correct signed_node_info for the chosen routing domain
let opt_current_sni = match routing_domain {
RoutingDomain::LocalNetwork => &mut self.local_network.signed_node_info,
RoutingDomain::PublicInternet => &mut self.public_internet.signed_node_info,
};
*opt_current_sni = None;
}
// Retuns true if the node info changed // Retuns true if the node info changed
pub fn update_signed_node_info( pub fn update_signed_node_info(
&mut self, &mut self,
routing_domain: RoutingDomain,
signed_node_info: SignedNodeInfo, signed_node_info: SignedNodeInfo,
allow_invalid_signature: bool, allow_invalid_signature: bool,
) { ) {
@ -150,7 +158,7 @@ impl BucketEntryInner {
} }
// Get the correct signed_node_info for the chosen routing domain // Get the correct signed_node_info for the chosen routing domain
let opt_current_sni = match routing_domain { let opt_current_sni = match signed_node_info.routing_domain {
RoutingDomain::LocalNetwork => &mut self.local_network.signed_node_info, RoutingDomain::LocalNetwork => &mut self.local_network.signed_node_info,
RoutingDomain::PublicInternet => &mut self.public_internet.signed_node_info, RoutingDomain::PublicInternet => &mut self.public_internet.signed_node_info,
}; };
@ -160,7 +168,8 @@ impl BucketEntryInner {
// If the timestamp hasn't changed or is less, ignore this update // If the timestamp hasn't changed or is less, ignore this update
if signed_node_info.timestamp <= current_sni.timestamp { if signed_node_info.timestamp <= current_sni.timestamp {
// If we received a node update with the same timestamp // If we received a node update with the same timestamp
// we can make this node live again, but only if our network hasn't changed // we can make this node live again, but only if our network has recently changed
// which may make nodes that were unreachable now reachable with the same dialinfo
if !self.updated_since_last_network_change if !self.updated_since_last_network_change
&& signed_node_info.timestamp == current_sni.timestamp && signed_node_info.timestamp == current_sni.timestamp
{ {
@ -185,50 +194,34 @@ impl BucketEntryInner {
self.touch_last_seen(intf::get_timestamp()); self.touch_last_seen(intf::get_timestamp());
} }
pub fn has_node_info(&self, opt_routing_domain: Option<RoutingDomain>) -> bool { pub fn has_node_info(&self, routing_domain_set: RoutingDomainSet) -> bool {
if let Some(routing_domain) = opt_routing_domain { for routing_domain in routing_domain_set {
// Get the correct signed_node_info for the chosen routing domain // Get the correct signed_node_info for the chosen routing domain
let opt_current_sni = match routing_domain { let opt_current_sni = match routing_domain {
RoutingDomain::LocalNetwork => &mut self.local_network.signed_node_info, RoutingDomain::LocalNetwork => &mut self.local_network.signed_node_info,
RoutingDomain::PublicInternet => &mut self.public_internet.signed_node_info, RoutingDomain::PublicInternet => &mut self.public_internet.signed_node_info,
}; };
opt_current_sni.is_some() if opt_current_sni.is_some() {
} else { return true;
if self.local_network.signed_node_info.is_some() {
true
} else if self.public_internet.signed_node_info.is_some() {
true
} else {
false
} }
} }
false
} }
pub fn has_valid_signed_node_info(&self, opt_routing_domain: Option<RoutingDomain>) -> bool { pub fn has_valid_signed_node_info(&self, routing_domain_set: RoutingDomainSet) -> bool {
if let Some(routing_domain) = opt_routing_domain { for routing_domain in routing_domain_set {
// Get the correct signed_node_info for the chosen routing domain // Get the correct signed_node_info for the chosen routing domain
let opt_current_sni = match routing_domain { let opt_current_sni = match routing_domain {
RoutingDomain::LocalNetwork => &mut self.local_network.signed_node_info, RoutingDomain::LocalNetwork => &mut self.local_network.signed_node_info,
RoutingDomain::PublicInternet => &mut self.public_internet.signed_node_info, RoutingDomain::PublicInternet => &mut self.public_internet.signed_node_info,
}; };
if let Some(sni) = opt_current_sni { if let Some(sni) = opt_current_sni {
sni.is_valid()
} else {
false
}
} else {
if let Some(sni) = self.local_network.signed_node_info {
if sni.is_valid() { if sni.is_valid() {
return true; return true;
} }
} }
if let Some(sni) = self.public_internet.signed_node_info {
if sni.is_valid() {
return true;
}
}
false
} }
false
} }
pub fn node_info(&self, routing_domain: RoutingDomain) -> Option<NodeInfo> { pub fn node_info(&self, routing_domain: RoutingDomain) -> Option<NodeInfo> {
@ -250,8 +243,28 @@ impl BucketEntryInner {
}) })
} }
fn descriptor_to_key(last_connection: ConnectionDescriptor) -> LastConnectionKey { pub fn best_routing_domain(
&self,
routing_domain_set: RoutingDomainSet,
) -> Option<RoutingDomain> {
for routing_domain in routing_domain_set {
let opt_current_sni = match routing_domain {
RoutingDomain::LocalNetwork => &mut self.local_network.signed_node_info,
RoutingDomain::PublicInternet => &mut self.public_internet.signed_node_info,
};
if let Some(sni) = opt_current_sni {
if sni.is_valid() {
return Some(routing_domain);
}
}
}
None
}
fn descriptor_to_key(&self, last_connection: ConnectionDescriptor) -> LastConnectionKey {
let routing_domain = self.routing_domain_for_address(last_connection.remote().address());
LastConnectionKey( LastConnectionKey(
routing_domain,
last_connection.protocol_type(), last_connection.protocol_type(),
last_connection.address_type(), last_connection.address_type(),
) )
@ -259,7 +272,7 @@ impl BucketEntryInner {
// Stores a connection descriptor in this entry's table of last connections // Stores a connection descriptor in this entry's table of last connections
pub fn set_last_connection(&mut self, last_connection: ConnectionDescriptor, timestamp: u64) { pub fn set_last_connection(&mut self, last_connection: ConnectionDescriptor, timestamp: u64) {
let key = Self::descriptor_to_key(last_connection); let key = self.descriptor_to_key(last_connection);
self.last_connections self.last_connections
.insert(key, (last_connection, timestamp)); .insert(key, (last_connection, timestamp));
} }
@ -269,18 +282,21 @@ impl BucketEntryInner {
self.last_connections.clear(); self.last_connections.clear();
} }
// Gets the best 'last connection' that matches a set of protocol types and address types // Gets the best 'last connection' that matches a set of routing domain, protocol types and address types
pub fn last_connection( pub fn last_connection(
&self, &self,
routing_domain_set: RoutingDomainSet,
dial_info_filter: Option<DialInfoFilter>, dial_info_filter: Option<DialInfoFilter>,
) -> Option<(ConnectionDescriptor, u64)> { ) -> Option<(ConnectionDescriptor, u64)> {
// Iterate peer scopes and protocol types and address type in order to ensure we pick the preferred protocols if all else is the same // Iterate peer scopes and protocol types and address type in order to ensure we pick the preferred protocols if all else is the same
let dif = dial_info_filter.unwrap_or_default(); let dif = dial_info_filter.unwrap_or_default();
for pt in dif.protocol_type_set { for rd in routing_domain_set {
for at in dif.address_type_set { for pt in dif.protocol_type_set {
let key = LastConnectionKey(pt, at); for at in dif.address_type_set {
if let Some(v) = self.last_connections.get(&key) { let key = LastConnectionKey(rd, pt, at);
return Some(*v); if let Some(v) = self.last_connections.get(&key) {
return Some(*v);
}
} }
} }
} }
@ -325,7 +341,7 @@ impl BucketEntryInner {
.node_status .node_status
.map(|ln| NodeStatus::LocalNetwork(ln)), .map(|ln| NodeStatus::LocalNetwork(ln)),
RoutingDomain::PublicInternet => self RoutingDomain::PublicInternet => self
.local_network .public_internet
.node_status .node_status
.map(|pi| NodeStatus::PublicInternet(pi)), .map(|pi| NodeStatus::PublicInternet(pi)),
} }

View File

@ -122,7 +122,7 @@ impl RoutingTable {
let entry = v.unwrap(); let entry = v.unwrap();
entry.with(|e| { entry.with(|e| {
// skip nodes on our local network here // skip nodes on our local network here
if e.has_node_info(Some(RoutingDomain::LocalNetwork)) { if e.has_node_info(RoutingDomainSet::only(RoutingDomain::LocalNetwork)) {
return false; return false;
} }
@ -130,25 +130,22 @@ impl RoutingTable {
let filter = |n: NodeInfo| { let filter = |n: NodeInfo| {
let mut keep = false; let mut keep = false;
for did in n.dial_info_detail_list { for did in n.dial_info_detail_list {
if did.dial_info.is_global() { if matches!(did.dial_info.address_type(), AddressType::IPV4) {
if matches!(did.dial_info.address_type(), AddressType::IPV4) { for (n, protocol_type) in protocol_types.iter().enumerate() {
for (n, protocol_type) in protocol_types.iter().enumerate() { if nodes_proto_v4[n] < max_per_type
if nodes_proto_v4[n] < max_per_type && did.dial_info.protocol_type() == *protocol_type
&& did.dial_info.protocol_type() == *protocol_type {
{ nodes_proto_v4[n] += 1;
nodes_proto_v4[n] += 1; keep = true;
keep = true;
}
} }
} else if matches!(did.dial_info.address_type(), AddressType::IPV6) }
{ } else if matches!(did.dial_info.address_type(), AddressType::IPV6) {
for (n, protocol_type) in protocol_types.iter().enumerate() { for (n, protocol_type) in protocol_types.iter().enumerate() {
if nodes_proto_v6[n] < max_per_type if nodes_proto_v6[n] < max_per_type
&& did.dial_info.protocol_type() == *protocol_type && did.dial_info.protocol_type() == *protocol_type
{ {
nodes_proto_v6[n] += 1; nodes_proto_v6[n] += 1;
keep = true; keep = true;
}
} }
} }
} }
@ -168,48 +165,16 @@ impl RoutingTable {
) )
} }
// Get our own node's peer info (public node info) so we can share it with other nodes
pub fn get_own_peer_info(&self, routing_domain: RoutingDomain) -> PeerInfo {
PeerInfo::new(
NodeId::new(self.node_id()),
self.get_own_signed_node_info(routing_domain),
)
}
pub fn get_own_signed_node_info(&self, routing_domain: RoutingDomain) -> SignedNodeInfo {
let node_id = NodeId::new(self.node_id());
let secret = self.node_id_secret();
SignedNodeInfo::with_secret(self.get_own_node_info(routing_domain), node_id, &secret)
.unwrap()
}
pub fn get_own_node_info(&self, routing_domain: RoutingDomain) -> NodeInfo {
let netman = self.network_manager();
let relay_node = self.relay_node(routing_domain);
let pc = netman.get_protocol_config();
NodeInfo {
network_class: netman
.get_network_class(routing_domain)
.unwrap_or(NetworkClass::Invalid),
outbound_protocols: pc.outbound,
address_types: pc.family_global,
min_version: MIN_VERSION,
max_version: MAX_VERSION,
dial_info_detail_list: self.dial_info_details(routing_domain),
relay_peer_info: relay_node.and_then(|rn| rn.peer_info(routing_domain).map(Box::new)),
}
}
pub fn filter_has_valid_signed_node_info( pub fn filter_has_valid_signed_node_info(
&self, &self,
v: Option<Arc<BucketEntry>>, v: Option<Arc<BucketEntry>>,
own_peer_info_is_valid: bool, own_peer_info_is_valid: bool,
opt_routing_domain: Option<RoutingDomain>, routing_domain_set: RoutingDomainSet,
) -> bool { ) -> bool {
let routing_table = self.clone(); let routing_table = self.clone();
match v { match v {
None => own_peer_info_is_valid, None => own_peer_info_is_valid,
Some(entry) => entry.with(|e| e.has_valid_signed_node_info(opt_routing_domain)), Some(entry) => entry.with(|e| e.has_valid_signed_node_info(routing_domain_set)),
} }
} }
@ -425,7 +390,7 @@ impl RoutingTable {
let mut protocol_to_port = let mut protocol_to_port =
BTreeMap::<(ProtocolType, AddressType), (LowLevelProtocolType, u16)>::new(); BTreeMap::<(ProtocolType, AddressType), (LowLevelProtocolType, u16)>::new();
let our_dids = self.all_filtered_dial_info_details( let our_dids = self.all_filtered_dial_info_details(
Some(RoutingDomain::PublicInternet), RoutingDomainSet::only(RoutingDomain::PublicInternet),
&DialInfoFilter::all(), &DialInfoFilter::all(),
); );
for did in our_dids { for did in our_dids {
@ -452,12 +417,12 @@ impl RoutingTable {
// Get all our outbound protocol/address types // Get all our outbound protocol/address types
let outbound_dif = self let outbound_dif = self
.network_manager() .network_manager()
.get_outbound_dial_info_filter(RoutingDomain::PublicInternet); .get_outbound_node_ref_filter(RoutingDomain::PublicInternet);
let mapped_port_info = self.get_mapped_port_info(); let mapped_port_info = self.get_mapped_port_info();
move |e: &BucketEntryInner| { move |e: &BucketEntryInner| {
// Ensure this node is not on the local network // Ensure this node is not on the local network
if e.has_node_info(Some(RoutingDomain::LocalNetwork)) { if e.has_node_info(RoutingDomainSet::only(RoutingDomain::LocalNetwork)) {
return false; return false;
} }
@ -542,11 +507,7 @@ impl RoutingTable {
} }
#[instrument(level = "trace", skip(self), ret)] #[instrument(level = "trace", skip(self), ret)]
pub fn register_find_node_answer( pub fn register_find_node_answer(&self, peers: Vec<PeerInfo>) -> Vec<NodeRef> {
&self,
routing_domain: RoutingDomain,
peers: Vec<PeerInfo>,
) -> Vec<NodeRef> {
let node_id = self.node_id(); let node_id = self.node_id();
// register nodes we'd found // register nodes we'd found
@ -566,7 +527,7 @@ impl RoutingTable {
// register the node if it's new // register the node if it's new
if let Some(nr) = self.register_node_with_signed_node_info( if let Some(nr) = self.register_node_with_signed_node_info(
routing_domain, RoutingDomain::PublicInternet,
p.node_id.key, p.node_id.key,
p.signed_node_info.clone(), p.signed_node_info.clone(),
false, false,
@ -580,7 +541,6 @@ impl RoutingTable {
#[instrument(level = "trace", skip(self), ret, err)] #[instrument(level = "trace", skip(self), ret, err)]
pub async fn find_node( pub async fn find_node(
&self, &self,
routing_domain: RoutingDomain,
node_ref: NodeRef, node_ref: NodeRef,
node_id: DHTKey, node_id: DHTKey,
) -> EyreResult<NetworkResult<Vec<NodeRef>>> { ) -> EyreResult<NetworkResult<Vec<NodeRef>>> {
@ -589,18 +549,13 @@ impl RoutingTable {
let res = network_result_try!( let res = network_result_try!(
rpc_processor rpc_processor
.clone() .clone()
.rpc_call_find_node( .rpc_call_find_node(Destination::direct(node_ref), node_id,)
Destination::direct(node_ref.clone()).with_routing_domain(routing_domain),
node_id,
None,
rpc_processor.make_respond_to_sender(routing_domain, node_ref.clone()),
)
.await? .await?
); );
// register nodes we'd found // register nodes we'd found
Ok(NetworkResult::value( Ok(NetworkResult::value(
self.register_find_node_answer(routing_domain, res.answer), self.register_find_node_answer(res.answer),
)) ))
} }

View File

@ -3,6 +3,7 @@ mod bucket_entry;
mod debug; mod debug;
mod find_nodes; mod find_nodes;
mod node_ref; mod node_ref;
mod routing_domains;
mod stats_accounting; mod stats_accounting;
mod tasks; mod tasks;
@ -17,34 +18,31 @@ pub use debug::*;
pub use find_nodes::*; pub use find_nodes::*;
use hashlink::LruCache; use hashlink::LruCache;
pub use node_ref::*; pub use node_ref::*;
pub use routing_domains::*;
pub use stats_accounting::*; pub use stats_accounting::*;
const RECENT_PEERS_TABLE_SIZE: usize = 64; const RECENT_PEERS_TABLE_SIZE: usize = 64;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#[derive(Debug, Default)]
pub struct RoutingDomainDetail {
relay_node: Option<NodeRef>,
dial_info_details: Vec<DialInfoDetail>,
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct RecentPeersEntry { pub struct RecentPeersEntry {
last_connection: ConnectionDescriptor, last_connection: ConnectionDescriptor,
} }
/// RoutingTable rwlock-internal data
struct RoutingTableInner { struct RoutingTableInner {
network_manager: NetworkManager, network_manager: NetworkManager,
node_id: DHTKey, // The current node's public DHT key // The current node's public DHT key
node_id: DHTKey,
node_id_secret: DHTKeySecret, // The current node's DHT key secret node_id_secret: DHTKeySecret, // The current node's DHT key secret
buckets: Vec<Bucket>, // Routing table buckets that hold entries buckets: Vec<Bucket>, // Routing table buckets that hold entries
kick_queue: BTreeSet<usize>, // Buckets to kick on our next kick task kick_queue: BTreeSet<usize>, // Buckets to kick on our next kick task
bucket_entry_count: usize, // A fast counter for the number of entries in the table, total bucket_entry_count: usize, // A fast counter for the number of entries in the table, total
public_internet_routing_domain: RoutingDomainDetail, // The dial info we use on the public internet public_internet_routing_domain: PublicInternetRoutingDomainDetail, // The public internet
local_network_routing_domain: RoutingDomainDetail, // The dial info we use on the local network local_network_routing_domain: LocalInternetRoutingDomainDetail, // The dial info we use on the local network
self_latency_stats_accounting: LatencyStatsAccounting, // Interim accounting mechanism for this node's RPC latency to any other node self_latency_stats_accounting: LatencyStatsAccounting, // Interim accounting mechanism for this node's RPC latency to any other node
self_transfer_stats_accounting: TransferStatsAccounting, // Interim accounting mechanism for the total bandwidth to/from this node self_transfer_stats_accounting: TransferStatsAccounting, // Interim accounting mechanism for the total bandwidth to/from this node
@ -80,8 +78,8 @@ impl RoutingTable {
node_id_secret: DHTKeySecret::default(), node_id_secret: DHTKeySecret::default(),
buckets: Vec::new(), buckets: Vec::new(),
kick_queue: BTreeSet::default(), kick_queue: BTreeSet::default(),
public_internet_routing_domain: RoutingDomainDetail::default(), public_internet_routing_domain: PublicInternetRoutingDomainDetail::default(),
local_network_routing_domain: RoutingDomainDetail::default(), local_network_routing_domain: LocalInternetRoutingDomainDetail::default(),
bucket_entry_count: 0, bucket_entry_count: 0,
self_latency_stats_accounting: LatencyStatsAccounting::new(), self_latency_stats_accounting: LatencyStatsAccounting::new(),
self_transfer_stats_accounting: TransferStatsAccounting::new(), self_transfer_stats_accounting: TransferStatsAccounting::new(),
@ -140,9 +138,21 @@ impl RoutingTable {
self.inner.read().node_id_secret self.inner.read().node_id_secret
} }
pub fn routing_domain_for_address(&self, address: Address) -> Option<RoutingDomain> {
let inner = self.inner.read();
for rd in RoutingDomain::all() {
let can_contain =
Self::with_routing_domain(&*inner, rd, |rdd| rdd.can_contain_address(address));
if can_contain {
return Some(rd);
}
}
None
}
fn with_routing_domain<F, R>(inner: &RoutingTableInner, domain: RoutingDomain, f: F) -> R fn with_routing_domain<F, R>(inner: &RoutingTableInner, domain: RoutingDomain, f: F) -> R
where where
F: FnOnce(&RoutingDomainDetail) -> R, F: FnOnce(&dyn RoutingDomainDetail) -> R,
{ {
match domain { match domain {
RoutingDomain::PublicInternet => f(&inner.public_internet_routing_domain), RoutingDomain::PublicInternet => f(&inner.public_internet_routing_domain),
@ -156,7 +166,7 @@ impl RoutingTable {
f: F, f: F,
) -> R ) -> R
where where
F: FnOnce(&mut RoutingDomainDetail) -> R, F: FnOnce(&mut dyn RoutingDomainDetail) -> R,
{ {
match domain { match domain {
RoutingDomain::PublicInternet => f(&mut inner.public_internet_routing_domain), RoutingDomain::PublicInternet => f(&mut inner.public_internet_routing_domain),
@ -166,79 +176,56 @@ impl RoutingTable {
pub fn relay_node(&self, domain: RoutingDomain) -> Option<NodeRef> { pub fn relay_node(&self, domain: RoutingDomain) -> Option<NodeRef> {
let inner = self.inner.read(); let inner = self.inner.read();
Self::with_routing_domain(&*inner, domain, |rd| rd.relay_node.clone()) Self::with_routing_domain(&*inner, domain, |rd| rd.relay_node())
} }
pub fn set_relay_node(&self, domain: RoutingDomain, opt_relay_node: Option<NodeRef>) { pub fn set_relay_node(&self, domain: RoutingDomain, opt_relay_node: Option<NodeRef>) {
let inner = self.inner.write(); let inner = self.inner.write();
Self::with_routing_domain(&mut *inner, domain, |rd| rd.relay_node = opt_relay_node); Self::with_routing_domain_mut(&mut *inner, domain, |rd| rd.set_relay_node(opt_relay_node));
} }
pub fn has_dial_info(&self, domain: RoutingDomain) -> bool { pub fn has_dial_info(&self, domain: RoutingDomain) -> bool {
let inner = self.inner.read(); let inner = self.inner.read();
Self::with_routing_domain(&*inner, domain, |rd| !rd.dial_info_details.is_empty()) Self::with_routing_domain(&*inner, domain, |rd| !rd.dial_info_details().is_empty())
} }
pub fn dial_info_details(&self, domain: RoutingDomain) -> Vec<DialInfoDetail> { pub fn dial_info_details(&self, domain: RoutingDomain) -> Vec<DialInfoDetail> {
let inner = self.inner.read(); let inner = self.inner.read();
Self::with_routing_domain(&*inner, domain, |rd| rd.dial_info_details.clone()) Self::with_routing_domain(&*inner, domain, |rd| rd.dial_info_details().clone())
} }
pub fn first_filtered_dial_info_detail( pub fn first_filtered_dial_info_detail(
&self, &self,
domain: Option<RoutingDomain>, routing_domain_set: RoutingDomainSet,
filter: &DialInfoFilter, filter: &DialInfoFilter,
) -> Option<DialInfoDetail> { ) -> Option<DialInfoDetail> {
let inner = self.inner.read(); let inner = self.inner.read();
// Prefer local network first if it isn't filtered out for routing_domain in routing_domain_set {
if domain == None || domain == Some(RoutingDomain::LocalNetwork) { let did = Self::with_routing_domain(&*inner, routing_domain, |rd| {
Self::with_routing_domain(&*inner, RoutingDomain::LocalNetwork, |rd| { for did in rd.dial_info_details() {
for did in &rd.dial_info_details {
if did.matches_filter(filter) { if did.matches_filter(filter) {
return Some(did.clone()); return Some(did.clone());
} }
} }
None None
}) });
} else { if did.is_some() {
None return did;
}
.or_else(|| {
if domain == None || domain == Some(RoutingDomain::PublicInternet) {
Self::with_routing_domain(&*inner, RoutingDomain::PublicInternet, |rd| {
for did in &rd.dial_info_details {
if did.matches_filter(filter) {
return Some(did.clone());
}
}
None
})
} else {
None
} }
}) }
None
} }
pub fn all_filtered_dial_info_details( pub fn all_filtered_dial_info_details(
&self, &self,
domain: Option<RoutingDomain>, routing_domain_set: RoutingDomainSet,
filter: &DialInfoFilter, filter: &DialInfoFilter,
) -> Vec<DialInfoDetail> { ) -> Vec<DialInfoDetail> {
let inner = self.inner.read(); let inner = self.inner.read();
let mut ret = Vec::new(); let mut ret = Vec::new();
for routing_domain in routing_domain_set {
if domain == None || domain == Some(RoutingDomain::LocalNetwork) { Self::with_routing_domain(&*inner, routing_domain, |rd| {
Self::with_routing_domain(&*inner, RoutingDomain::LocalNetwork, |rd| { for did in rd.dial_info_details() {
for did in &rd.dial_info_details {
if did.matches_filter(filter) {
ret.push(did.clone());
}
}
});
}
if domain == None || domain == Some(RoutingDomain::PublicInternet) {
Self::with_routing_domain(&*inner, RoutingDomain::PublicInternet, |rd| {
for did in &rd.dial_info_details {
if did.matches_filter(filter) { if did.matches_filter(filter) {
ret.push(did.clone()); ret.push(did.clone());
} }
@ -250,17 +237,13 @@ impl RoutingTable {
} }
pub fn ensure_dial_info_is_valid(&self, domain: RoutingDomain, dial_info: &DialInfo) -> bool { pub fn ensure_dial_info_is_valid(&self, domain: RoutingDomain, dial_info: &DialInfo) -> bool {
let enable_local_peer_scope = { let address = dial_info.socket_address().address();
let config = self.network_manager().config(); let inner = self.inner.read();
let c = config.get(); let can_contain_address =
c.network.enable_local_peer_scope Self::with_routing_domain(&*inner, domain, |rd| rd.can_contain_address(address));
};
if !enable_local_peer_scope if !can_contain_address {
&& matches!(domain, RoutingDomain::PublicInternet) log_rtab!(debug "can not add dial info to this routing domain");
&& dial_info.is_local()
{
log_rtab!(debug "shouldn't be registering local addresses as public");
return false; return false;
} }
if !dial_info.is_valid() { if !dial_info.is_valid() {
@ -281,25 +264,20 @@ impl RoutingTable {
class: DialInfoClass, class: DialInfoClass,
) -> EyreResult<()> { ) -> EyreResult<()> {
if !self.ensure_dial_info_is_valid(domain, &dial_info) { if !self.ensure_dial_info_is_valid(domain, &dial_info) {
return Err(eyre!("dial info is not valid")); return Err(eyre!("dial info is not valid in this routing domain"));
} }
let mut inner = self.inner.write(); let mut inner = self.inner.write();
Self::with_routing_domain_mut(&mut *inner, domain, |rd| { Self::with_routing_domain_mut(&mut *inner, domain, |rd| {
rd.dial_info_details.push(DialInfoDetail { rd.add_dial_info_detail(DialInfoDetail {
dial_info: dial_info.clone(), dial_info: dial_info.clone(),
class, class,
}); });
rd.dial_info_details.sort();
}); });
let domain_str = match domain {
RoutingDomain::PublicInternet => "Public",
RoutingDomain::LocalNetwork => "Local",
};
info!( info!(
"{} Dial Info: {}", "{:?} Dial Info: {}",
domain_str, domain,
NodeDialInfo { NodeDialInfo {
node_id: NodeId::new(inner.node_id), node_id: NodeId::new(inner.node_id),
dial_info dial_info
@ -308,19 +286,18 @@ impl RoutingTable {
); );
debug!(" Class: {:?}", class); debug!(" Class: {:?}", class);
// Public dial info changed, go through all nodes and reset their 'seen our node info' bit Self::reset_all_seen_our_node_info(&mut *inner, domain);
if matches!(domain, RoutingDomain::PublicInternet) { Self::reset_all_updated_since_last_network_change(&mut *inner);
Self::reset_all_seen_our_node_info(&mut *inner);
Self::reset_all_updated_since_last_network_change(&mut *inner);
}
Ok(()) Ok(())
} }
fn reset_all_seen_our_node_info(inner: &mut RoutingTableInner) { fn reset_all_seen_our_node_info(inner: &mut RoutingTableInner, routing_domain: RoutingDomain) {
let cur_ts = intf::get_timestamp(); let cur_ts = intf::get_timestamp();
Self::with_entries(&*inner, cur_ts, BucketEntryState::Dead, |_, v| { Self::with_entries(&*inner, cur_ts, BucketEntryState::Dead, |_, v| {
v.with_mut(|e| e.set_seen_our_node_info(false)); v.with_mut(|e| {
e.set_seen_our_node_info(routing_domain, false);
});
Option::<()>::None Option::<()>::None
}); });
} }
@ -333,20 +310,57 @@ impl RoutingTable {
}); });
} }
pub fn clear_dial_info_details(&self, domain: RoutingDomain) { pub fn clear_dial_info_details(&self, routing_domain: RoutingDomain) {
trace!("clearing dial info domain: {:?}", domain); trace!("clearing dial info domain: {:?}", routing_domain);
let mut inner = self.inner.write(); let mut inner = self.inner.write();
Self::with_routing_domain_mut(&mut *inner, domain, |rd| { Self::with_routing_domain_mut(&mut *inner, routing_domain, |rd| {
rd.dial_info_details.clear(); rd.clear_dial_info_details();
}); });
// Public dial info changed, go through all nodes and reset their 'seen our node info' bit // Public dial info changed, go through all nodes and reset their 'seen our node info' bit
if matches!(domain, RoutingDomain::PublicInternet) { Self::reset_all_seen_our_node_info(&mut *inner, routing_domain);
Self::reset_all_seen_our_node_info(&mut *inner); }
pub fn get_own_peer_info(&self, routing_domain: RoutingDomain) -> PeerInfo {
PeerInfo::new(
NodeId::new(self.node_id()),
self.get_own_signed_node_info(routing_domain),
)
}
pub fn get_own_signed_node_info(&self, routing_domain: RoutingDomain) -> SignedNodeInfo {
let node_id = NodeId::new(self.node_id());
let secret = self.node_id_secret();
SignedNodeInfo::with_secret(self.get_own_node_info(routing_domain), node_id, &secret)
.unwrap()
}
pub fn get_own_node_info(&self, routing_domain: RoutingDomain) -> NodeInfo {
let netman = self.network_manager();
let relay_node = self.relay_node(routing_domain);
let pc = netman.get_protocol_config();
NodeInfo {
network_class: netman
.get_network_class(routing_domain)
.unwrap_or(NetworkClass::Invalid),
outbound_protocols: pc.outbound,
address_types: pc.family_global,
min_version: MIN_VERSION,
max_version: MAX_VERSION,
dial_info_detail_list: self.dial_info_details(routing_domain),
relay_peer_info: relay_node.and_then(|rn| rn.peer_info(routing_domain).map(Box::new)),
} }
} }
pub fn has_valid_own_node_info(&self, routing_domain: RoutingDomain) -> bool {
let netman = self.network_manager();
let nc = netman
.get_network_class(routing_domain)
.unwrap_or(NetworkClass::Invalid);
!matches!(nc, NetworkClass::Invalid)
}
fn bucket_depth(index: usize) -> usize { fn bucket_depth(index: usize) -> usize {
match index { match index {
0 => 256, 0 => 256,
@ -398,6 +412,24 @@ impl RoutingTable {
debug!("finished routing table terminate"); debug!("finished routing table terminate");
} }
pub fn configure_local_network_routing_domain(&self, local_networks: Vec<(IpAddr, IpAddr)>) {
let mut inner = self.inner.write();
let changed = inner
.local_network_routing_domain
.set_local_networks(local_networks);
// If the local network topology has changed, nuke the existing local node info and let new local discovery happen
if changed {
let cur_ts = intf::get_timestamp();
Self::with_entries(&*inner, cur_ts, BucketEntryState::Dead, |_rti, e| {
e.with_mut(|e| {
e.clear_signed_node_info(RoutingDomain::LocalNetwork);
});
Option::<()>::None
});
}
}
// Attempt to empty the routing table // Attempt to empty the routing table
// should only be performed when there are no node_refs (detached) // should only be performed when there are no node_refs (detached)
pub fn purge_buckets(&self) { pub fn purge_buckets(&self) {
@ -461,16 +493,28 @@ impl RoutingTable {
.unwrap() .unwrap()
} }
pub fn get_entry_count(&self, min_state: BucketEntryState) -> usize { pub fn get_entry_count(
&self,
routing_domain_set: RoutingDomainSet,
min_state: BucketEntryState,
) -> usize {
let inner = self.inner.read(); let inner = self.inner.read();
Self::get_entry_count_inner(&*inner, min_state) Self::get_entry_count_inner(&*inner, routing_domain_set, min_state)
} }
fn get_entry_count_inner(inner: &RoutingTableInner, min_state: BucketEntryState) -> usize { fn get_entry_count_inner(
inner: &RoutingTableInner,
routing_domain_set: RoutingDomainSet,
min_state: BucketEntryState,
) -> usize {
let mut count = 0usize; let mut count = 0usize;
let cur_ts = intf::get_timestamp(); let cur_ts = intf::get_timestamp();
Self::with_entries(inner, cur_ts, min_state, |_, _| { Self::with_entries(inner, cur_ts, min_state, |_, e| {
count += 1; if e.with(|e| e.best_routing_domain(routing_domain_set))
.is_some()
{
count += 1;
}
Option::<()>::None Option::<()>::None
}); });
count count
@ -505,38 +549,32 @@ impl RoutingTable {
Self::with_entries(&*inner, cur_ts, BucketEntryState::Unreliable, |k, v| { Self::with_entries(&*inner, cur_ts, BucketEntryState::Unreliable, |k, v| {
// Only update nodes that haven't seen our node info yet // Only update nodes that haven't seen our node info yet
if all || !v.with(|e| e.has_seen_our_node_info(routing_domain)) { if all || !v.with(|e| e.has_seen_our_node_info(routing_domain)) {
node_refs.push(NodeRef::new( node_refs.push(NodeRef::new(self.clone(), k, v, None));
self.clone(),
k,
v,
RoutingDomainSet::only(routing_domain),
None,
));
} }
Option::<()>::None Option::<()>::None
}); });
node_refs node_refs
} }
pub fn get_nodes_needing_ping(&self, cur_ts: u64) -> Vec<NodeRef> { pub fn get_nodes_needing_ping(
&self,
routing_domain: RoutingDomain,
cur_ts: u64,
) -> Vec<NodeRef> {
let inner = self.inner.read(); let inner = self.inner.read();
// Collect relay nodes // Collect relay nodes
let mut relays: HashSet<DHTKey> = HashSet::new(); let opt_relay_id = Self::with_routing_domain(&*inner, routing_domain, |rd| {
for rd in RoutingDomain::all() { rd.relay_node().map(|rn| rn.node_id())
let opt_relay_id = });
Self::with_routing_domain(&*inner, RoutingDomain::PublicInternet, |rd| {
rd.relay_node.map(|rn| rn.node_id())
});
if let Some(relay_id) = opt_relay_id {
relays.insert(relay_id);
}
}
// Collect all entries that are 'needs_ping' and have some node info making them reachable somehow // Collect all entries that are 'needs_ping' and have some node info making them reachable somehow
let mut node_refs = Vec::<NodeRef>::with_capacity(inner.bucket_entry_count); let mut node_refs = Vec::<NodeRef>::with_capacity(inner.bucket_entry_count);
Self::with_entries(&*inner, cur_ts, BucketEntryState::Unreliable, |k, v| { Self::with_entries(&*inner, cur_ts, BucketEntryState::Unreliable, |k, v| {
if v.with(|e| e.has_node_info(None) && e.needs_ping(&k, cur_ts, relays.contains(&k))) { if v.with(|e| {
e.has_node_info(RoutingDomainSet::only(routing_domain))
&& e.needs_ping(&k, cur_ts, opt_relay_id == Some(k))
}) {
node_refs.push(NodeRef::new(self.clone(), k, v, None)); node_refs.push(NodeRef::new(self.clone(), k, v, None));
} }
Option::<()>::None Option::<()>::None
@ -599,7 +637,7 @@ impl RoutingTable {
// Kick the bucket // Kick the bucket
inner.kick_queue.insert(idx); inner.kick_queue.insert(idx);
log_rtab!(debug "Routing table now has {} nodes, {} live", cnt, Self::get_entry_count_inner(&mut *inner, BucketEntryState::Unreliable)); log_rtab!(debug "Routing table now has {} nodes, {} live", cnt, Self::get_entry_count_inner(&mut *inner, RoutingDomainSet::all(), BucketEntryState::Unreliable));
nr nr
} }
@ -635,7 +673,6 @@ impl RoutingTable {
// and add the dial info we have for it, since that's pretty common // and add the dial info we have for it, since that's pretty common
pub fn register_node_with_signed_node_info( pub fn register_node_with_signed_node_info(
&self, &self,
routing_domain: RoutingDomain,
node_id: DHTKey, node_id: DHTKey,
signed_node_info: SignedNodeInfo, signed_node_info: SignedNodeInfo,
allow_invalid_signature: bool, allow_invalid_signature: bool,
@ -651,9 +688,12 @@ impl RoutingTable {
return None; return None;
} }
} }
self.create_node_ref(node_id, |e| { self.create_node_ref(node_id, |e| {
e.update_signed_node_info(routing_domain, signed_node_info, allow_invalid_signature); e.update_signed_node_info(signed_node_info, allow_invalid_signature);
})
.map(|mut nr| {
nr.set_filter(Some(NodeRefFilter::new().with_routing_domain(signed_node_info.routing_domain)))
nr
}) })
} }

View File

@ -6,11 +6,71 @@ use alloc::fmt;
// We should ping them with some frequency and 30 seconds is typical timeout // We should ping them with some frequency and 30 seconds is typical timeout
const CONNECTIONLESS_TIMEOUT_SECS: u32 = 29; const CONNECTIONLESS_TIMEOUT_SECS: u32 = 29;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct NodeRefFilter {
pub routing_domain_set: RoutingDomainSet,
pub dial_info_filter: DialInfoFilter,
}
impl Default for NodeRefFilter {
fn default() -> Self {
self.new()
}
}
impl NodeRefFilter {
pub fn new() -> Self {
Self {
routing_domain_set: RoutingDomainSet::all(),
dial_info_filter: DialInfoFilter::all(),
}
}
pub fn with_routing_domain(mut self, routing_domain: RoutingDomain) -> Self {
self.routing_domain_set = RoutingDomainSet::only(routing_domain);
self
}
pub fn with_routing_domain_set(mut self, routing_domain_set: RoutingDomainSet) -> Self {
self.routing_domain_set = routing_domain_set;
self
}
pub fn with_dial_info_filter(mut self, dial_info_filter: DialInfoFilter) -> Self {
self.dial_info_filter = dial_info_filter;
self
}
pub fn with_protocol_type(mut self, protocol_type: ProtocolType) -> Self {
self.dial_info_filter = self.dial_info_filter.with_protocol_type(protocol_type);
self
}
pub fn with_protocol_type_set(mut self, protocol_set: ProtocolTypeSet) -> Self {
self.dial_info_filter = self.dial_info_filter.with_protocol_type_set(protocol_set);
self
}
pub fn with_address_type(mut self, address_type: AddressType) -> Self {
self.dial_info_filter = self.dial_info_filter.with_address_type(address_type);
self
}
pub fn with_address_type_set(mut self, address_set: AddressTypeSet) -> Self {
self.dial_info_filter = self.dial_info_filter.with_address_type_set(address_set);
self
}
pub fn filtered(mut self, other_filter: &NodeRefFilter) -> Self {
self.routing_domain_set &= other_filter.routing_domain_set;
self.dial_info_filter = self
.dial_info_filter
.filtered(&other_filter.dial_info_filter);
self
}
pub fn is_dead(&self) -> bool {
self.dial_info_filter.is_empty() || self.routing_domain_set.is_empty()
}
}
pub struct NodeRef { pub struct NodeRef {
routing_table: RoutingTable, routing_table: RoutingTable,
node_id: DHTKey, node_id: DHTKey,
entry: Arc<BucketEntry>, entry: Arc<BucketEntry>,
filter: Option<DialInfoFilter>, filter: Option<NodeRefFilter>,
#[cfg(feature = "tracking")] #[cfg(feature = "tracking")]
track_id: usize, track_id: usize,
} }
@ -20,7 +80,7 @@ impl NodeRef {
routing_table: RoutingTable, routing_table: RoutingTable,
node_id: DHTKey, node_id: DHTKey,
entry: Arc<BucketEntry>, entry: Arc<BucketEntry>,
filter: Option<DialInfoFilter>, filter: Option<NodeRefFilter>,
) -> Self { ) -> Self {
entry.ref_count.fetch_add(1u32, Ordering::Relaxed); entry.ref_count.fetch_add(1u32, Ordering::Relaxed);
@ -34,43 +94,7 @@ impl NodeRef {
} }
} }
pub fn node_id(&self) -> DHTKey { // Operate on entry accessors
self.node_id
}
pub fn filter_ref(&self) -> Option<&DialInfoFilter> {
self.filter.as_ref()
}
pub fn take_filter(&mut self) -> Option<DialInfoFilter> {
self.filter.take()
}
pub fn set_filter(&mut self, filter: Option<DialInfoFilter>) {
self.filter = filter
}
pub fn merge_filter(&mut self, filter: DialInfoFilter) {
if let Some(self_filter) = self.filter.take() {
self.filter = Some(self_filter.filtered(&filter));
} else {
self.filter = Some(filter);
}
}
pub fn filtered_clone(&self, filter: DialInfoFilter) -> Self {
let mut out = self.clone();
out.merge_filter(filter);
out
}
pub fn is_filter_dead(&self) -> bool {
if let Some(filter) = &self.filter {
filter.is_dead()
} else {
false
}
}
pub(super) fn operate<T, F>(&self, f: F) -> T pub(super) fn operate<T, F>(&self, f: F) -> T
where where
@ -88,17 +112,67 @@ impl NodeRef {
self.entry.with_mut(|e| f(inner, e)) self.entry.with_mut(|e| f(inner, e))
} }
pub fn peer_info(&self, routing_domain: RoutingDomain) -> Option<PeerInfo> { // Filtering
self.operate(|_rti, e| e.peer_info(self.node_id(), routing_domain))
pub fn filter_ref(&self) -> Option<&NodeRefFilter> {
self.filter.as_ref()
} }
pub fn has_valid_signed_node_info(&self, opt_routing_domain: Option<RoutingDomain>) -> bool {
self.operate(|_rti, e| e.has_valid_signed_node_info(opt_routing_domain)) pub fn take_filter(&mut self) -> Option<NodeRefFilter> {
self.filter.take()
} }
pub fn has_seen_our_node_info(&self, routing_domain: RoutingDomain) -> bool {
self.operate(|_rti, e| e.has_seen_our_node_info(routing_domain)) pub fn set_filter(&mut self, filter: Option<NodeRefFilter>) {
self.filter = filter
} }
pub fn set_seen_our_node_info(&self, routing_domain: RoutingDomain) {
self.operate_mut(|_rti, e| e.set_seen_our_node_info(routing_domain, true)); pub fn merge_filter(&mut self, filter: NodeRefFilter) {
if let Some(self_filter) = self.filter.take() {
self.filter = Some(self_filter.filtered(&filter));
} else {
self.filter = Some(filter);
}
}
pub fn filtered_clone(&self, filter: NodeRefFilter) -> Self {
let mut out = self.clone();
out.merge_filter(filter);
out
}
pub fn is_filter_dead(&self) -> bool {
if let Some(filter) = &self.filter {
filter.is_dead()
} else {
false
}
}
pub fn routing_domain_set(&self) -> RoutingDomainSet {
self.filter
.map(|f| f.routing_domain_set)
.unwrap_or(RoutingDomainSet::all())
}
pub fn best_routing_domain(&self) -> Option<RoutingDomain> {
self.operate(|_rti, e| {
e.best_routing_domain(
self.filter
.map(|f| f.routing_domain_set)
.unwrap_or(RoutingDomainSet::all()),
)
})
}
// Accessors
pub fn routing_table(&self) -> RoutingTable {
self.routing_table.clone()
}
pub fn node_id(&self) -> DHTKey {
self.node_id
}
pub fn has_valid_signed_node_info(&self) -> bool {
self.operate(|_rti, e| e.has_valid_signed_node_info(self.routing_domain_set()))
} }
pub fn has_updated_since_last_network_change(&self) -> bool { pub fn has_updated_since_last_network_change(&self) -> bool {
self.operate(|_rti, e| e.has_updated_since_last_network_change()) self.operate(|_rti, e| e.has_updated_since_last_network_change())
@ -106,24 +180,31 @@ impl NodeRef {
pub fn set_updated_since_last_network_change(&self) { pub fn set_updated_since_last_network_change(&self) {
self.operate_mut(|_rti, e| e.set_updated_since_last_network_change(true)); self.operate_mut(|_rti, e| e.set_updated_since_last_network_change(true));
} }
pub fn update_node_status(&self, node_status: NodeStatus) { pub fn update_node_status(&self, node_status: NodeStatus) {
self.operate_mut(|_rti, e| { self.operate_mut(|_rti, e| {
e.update_node_status(node_status); e.update_node_status(node_status);
}); });
} }
pub fn min_max_version(&self) -> Option<(u8, u8)> { pub fn min_max_version(&self) -> Option<(u8, u8)> {
self.operate(|_rti, e| e.min_max_version()) self.operate(|_rti, e| e.min_max_version())
} }
pub fn set_min_max_version(&self, min_max_version: (u8, u8)) { pub fn set_min_max_version(&self, min_max_version: (u8, u8)) {
self.operate_mut(|_rti, e| e.set_min_max_version(min_max_version)) self.operate_mut(|_rti, e| e.set_min_max_version(min_max_version))
} }
pub fn state(&self, cur_ts: u64) -> BucketEntryState { pub fn state(&self, cur_ts: u64) -> BucketEntryState {
self.operate(|_rti, e| e.state(cur_ts)) self.operate(|_rti, e| e.state(cur_ts))
} }
// Per-RoutingDomain accessors
pub fn peer_info(&self, routing_domain: RoutingDomain) -> Option<PeerInfo> {
self.operate(|_rti, e| e.peer_info(self.node_id(), routing_domain))
}
pub fn has_seen_our_node_info(&self, routing_domain: RoutingDomain) -> bool {
self.operate(|_rti, e| e.has_seen_our_node_info(routing_domain))
}
pub fn set_seen_our_node_info(&self, routing_domain: RoutingDomain) {
self.operate_mut(|_rti, e| e.set_seen_our_node_info(routing_domain, true));
}
pub fn network_class(&self, routing_domain: RoutingDomain) -> Option<NetworkClass> { pub fn network_class(&self, routing_domain: RoutingDomain) -> Option<NetworkClass> {
self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.network_class)) self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.network_class))
} }
@ -143,7 +224,6 @@ impl NodeRef {
} }
dif dif
} }
pub fn relay(&self, routing_domain: RoutingDomain) -> Option<NodeRef> { pub fn relay(&self, routing_domain: RoutingDomain) -> Option<NodeRef> {
let target_rpi = let target_rpi =
self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.relay_peer_info))?; self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.relay_peer_info))?;
@ -155,83 +235,50 @@ impl NodeRef {
} }
// Register relay node and return noderef // Register relay node and return noderef
self.routing_table self.routing_table.register_node_with_signed_node_info(
.register_node_with_signed_node_info( t.node_id.key,
routing_domain, t.signed_node_info,
t.node_id.key, false,
t.signed_node_info, )
false,
)
.map(|mut nr| {
nr.set_filter(self.filter_ref().cloned());
nr
})
})
}
pub fn first_filtered_dial_info_detail(
&self,
routing_domain: Option<RoutingDomain>,
) -> Option<DialInfoDetail> {
self.operate(|_rt, e| {
// Prefer local dial info first unless it is filtered out
if routing_domain == None || routing_domain == Some(RoutingDomain::LocalNetwork) {
e.node_info(RoutingDomain::LocalNetwork).and_then(|l| {
l.first_filtered_dial_info_detail(|did| {
if let Some(filter) = self.filter.as_ref() {
did.matches_filter(filter)
} else {
true
}
})
})
} else {
None
}
.or_else(|| {
if routing_domain == None || routing_domain == Some(RoutingDomain::PublicInternet) {
e.node_info(RoutingDomain::PublicInternet).and_then(|n| {
n.first_filtered_dial_info_detail(|did| {
if let Some(filter) = self.filter.as_ref() {
did.matches_filter(filter)
} else {
true
}
})
})
} else {
None
}
})
}) })
} }
pub fn all_filtered_dial_info_details<F>( // Filtered accessors
&self, pub fn first_filtered_dial_info_detail(&self) -> Option<DialInfoDetail> {
routing_domain: Option<RoutingDomain>, let routing_domain_set = self.routing_domain_set();
) -> Vec<DialInfoDetail> {
let mut out = Vec::new();
self.operate(|_rt, e| { self.operate(|_rt, e| {
// Prefer local dial info first unless it is filtered out for routing_domain in routing_domain_set {
if routing_domain == None || routing_domain == Some(RoutingDomain::LocalNetwork) { if let Some(ni) = e.node_info(routing_domain) {
if let Some(ni) = e.node_info(RoutingDomain::LocalNetwork) { let filter = |did: &DialInfoDetail| {
out.append(&mut ni.all_filtered_dial_info_details(|did| { self.filter
if let Some(filter) = self.filter.as_ref() { .as_ref()
did.matches_filter(filter) .map(|f| did.matches_filter(f))
} else { .unwrap_or(true)
true };
} if let Some(did) = ni.first_filtered_dial_info_detail(filter) {
})) return Some(did);
}
} }
} }
if routing_domain == None || routing_domain == Some(RoutingDomain::PublicInternet) { None
if let Some(ni) = e.node_info(RoutingDomain::PublicInternet) { })
out.append(&mut ni.all_filtered_dial_info_details(|did| { }
if let Some(filter) = self.filter.as_ref() {
did.matches_filter(filter) pub fn all_filtered_dial_info_details<F>(&self) -> Vec<DialInfoDetail> {
} else { let routing_domain_set = self.routing_domain_set();
true let mut out = Vec::new();
} self.operate(|_rt, e| {
})) for routing_domain in routing_domain_set {
if let Some(ni) = e.node_info(routing_domain) {
let filter = |did: &DialInfoDetail| {
self.filter
.as_ref()
.map(|f| did.matches_filter(f))
.unwrap_or(true)
};
if let Some(did) = ni.first_filtered_dial_info_detail(filter) {
out.push(did);
}
} }
} }
}); });
@ -241,8 +288,12 @@ impl NodeRef {
pub async fn last_connection(&self) -> Option<ConnectionDescriptor> { pub async fn last_connection(&self) -> Option<ConnectionDescriptor> {
// Get the last connection and the last time we saw anything with this connection // Get the last connection and the last time we saw anything with this connection
let (last_connection, last_seen) = let (last_connection, last_seen) = self.operate(|_rti, e| {
self.operate(|_rti, e| e.last_connection(self.filter.clone()))?; e.last_connection(
self.filter.routing_domain_set,
self.filter.dial_info_filter.clone(),
)
})?;
// Should we check the connection table? // Should we check the connection table?
if last_connection.protocol_type().is_connection_oriented() { if last_connection.protocol_type().is_connection_oriented() {

View File

@ -0,0 +1,94 @@
use super::*;
/// General trait for all routing domains
pub trait RoutingDomainDetail {
fn can_contain_address(&self, address: Address) -> bool;
fn relay_node(&self) -> Option<NodeRef>;
fn set_relay_node(&mut self, opt_relay_node: Option<NodeRef>);
fn dial_info_details(&self) -> &Vec<DialInfoDetail>;
fn clear_dial_info_details(&mut self);
fn add_dial_info_detail(&mut self, did: DialInfoDetail);
}
/// Public Internet routing domain internals
#[derive(Debug, Default)]
pub struct PublicInternetRoutingDomainDetail {
/// An optional node we relay through for this domain
relay_node: Option<NodeRef>,
/// The dial infos on this domain we can be reached by
dial_info_details: Vec<DialInfoDetail>,
}
impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
fn can_contain_address(&self, address: Address) -> bool {
address.is_global()
}
fn relay_node(&self) -> Option<NodeRef> {
self.relay_node.clone()
}
fn set_relay_node(&mut self, opt_relay_node: Option<NodeRef>) {
self.relay_node = opt_relay_node
.map(|nr| nr.filtered_clone(NodeRefFilter::new().with_routing_domain(PublicInternet)))
}
fn dial_info_details(&self) -> &Vec<DialInfoDetail> {
&self.dial_info_details
}
fn clear_dial_info_details(&mut self) {
self.dial_info_details.clear();
}
fn add_dial_info_detail(&mut self, did: DialInfoDetail) {
self.dial_info_details.push(did);
self.dial_info_details.sort();
}
}
/// Local Network routing domain internals
#[derive(Debug, Default)]
pub struct LocalInternetRoutingDomainDetail {
/// An optional node we relay through for this domain
relay_node: Option<NodeRef>,
/// The dial infos on this domain we can be reached by
dial_info_details: Vec<DialInfoDetail>,
/// The local networks this domain will communicate with
local_networks: Vec<(IpAddr, IpAddr)>,
}
impl LocalInternetRoutingDomainDetail {
pub fn set_local_networks(&mut self, local_networks: Vec<(IpAddr, IpAddr)>) -> bool {
local_networks.sort();
if local_networks == self.local_networks {
return false;
}
self.local_networks = local_networks;
true
}
}
impl RoutingDomainDetail for LocalInternetRoutingDomainDetail {
fn can_contain_address(&self, address: Address) -> bool {
let ip = address.to_ip_addr();
for localnet in self.local_networks {
if ipaddr_in_network(ip, localnet.0, localnet.1) {
return true;
}
}
false
}
fn relay_node(&self) -> Option<NodeRef> {
self.relay_node.clone()
}
fn set_relay_node(&mut self, opt_relay_node: Option<NodeRef>) {
self.relay_node = opt_relay_node
.map(|nr| nr.filtered_clone(NodeRefFilter::new().with_routing_domain(LocalNetwork)));
}
fn dial_info_details(&self) -> &Vec<DialInfoDetail> {
&self.dial_info_details
}
fn clear_dial_info_details(&mut self) {
self.dial_info_details.clear();
}
fn add_dial_info_detail(&mut self, did: DialInfoDetail) {
self.dial_info_details.push(did);
self.dial_info_details.sort();
}
}

View File

@ -1,9 +1,9 @@
use crate::*; use crate::*;
use rpc_processor::*; use rpc_processor::*;
pub fn encode_node_status( pub fn encode_public_internet_node_status(
node_status: &NodeStatus, public_internet_node_status: &PublicInternetNodeStatus,
builder: &mut veilid_capnp::node_status::Builder, builder: &mut veilid_capnp::public_internet_node_status::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
builder.set_will_route(node_status.will_route); builder.set_will_route(node_status.will_route);
builder.set_will_tunnel(node_status.will_tunnel); builder.set_will_tunnel(node_status.will_tunnel);
@ -14,10 +14,10 @@ pub fn encode_node_status(
Ok(()) Ok(())
} }
pub fn decode_node_status( pub fn decode_public_internet_node_status(
reader: &veilid_capnp::node_status::Reader, reader: &veilid_capnp::public_internet_node_status::Reader,
) -> Result<NodeStatus, RPCError> { ) -> Result<PublicInternetNodeStatus, RPCError> {
Ok(NodeStatus { Ok(PublicInternetNodeStatus {
will_route: reader.reborrow().get_will_route(), will_route: reader.reborrow().get_will_route(),
will_tunnel: reader.reborrow().get_will_tunnel(), will_tunnel: reader.reborrow().get_will_tunnel(),
will_signal: reader.reborrow().get_will_signal(), will_signal: reader.reborrow().get_will_signal(),
@ -25,3 +25,62 @@ pub fn decode_node_status(
will_validate_dial_info: reader.reborrow().get_will_validate_dial_info(), will_validate_dial_info: reader.reborrow().get_will_validate_dial_info(),
}) })
} }
pub fn encode_local_network_node_status(
local_network_node_status: &LocalNetworkNodeStatus,
builder: &mut veilid_capnp::local_network_node_status::Builder,
) -> Result<(), RPCError> {
builder.set_will_relay(node_status.will_relay);
builder.set_will_validate_dial_info(node_status.will_validate_dial_info);
Ok(())
}
pub fn decode_local_network_node_status(
reader: &veilid_capnp::local_network_node_status::Reader,
) -> Result<LocalNetworkNodeStatus, RPCError> {
Ok(NodeStatus {
will_relay: reader.reborrow().get_will_relay(),
will_validate_dial_info: reader.reborrow().get_will_validate_dial_info(),
})
}
pub fn encode_node_status(
node_status: &NodeStatus,
builder: &mut veilid_capnp::node_status::Builder,
) -> Result<(), RPCError> {
match node_status {
NodeStatus::PublicInternetNodeStatus(ns) => {
let mut pi_builder = builder.reborrow().init_public_internet();
encode_public_internet_node_status(&ns, &mut pi_builder)
}
NodeStatus::LocalNetworkNodeStatus(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,
) -> Result<NodeStatus, RPCError> {
Ok(
match reader
.which()
.map_err(RPCError::map_internal("invalid node status"))?
{
veilid_capnp::node_status::PublicInternet(pi) => {
let r = r.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)
}
},
)
}

View File

@ -58,26 +58,34 @@ impl RPCOperationKind {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RPCOperation { pub struct RPCOperation {
op_id: u64, op_id: u64,
sender_info: Option<SignedNodeInfo>,
kind: RPCOperationKind, kind: RPCOperationKind,
} }
impl RPCOperation { impl RPCOperation {
pub fn new_question(question: RPCQuestion) -> Self { pub fn new_question(question: RPCQuestion, sender_info: Option<SignedNodeInfo>) -> Self {
Self { Self {
op_id: intf::get_random_u64(), op_id: intf::get_random_u64(),
sender_info,
kind: RPCOperationKind::Question(question), kind: RPCOperationKind::Question(question),
} }
} }
pub fn new_statement(statement: RPCStatement) -> Self { pub fn new_statement(statement: RPCStatement, sender_info: Option<SignedNodeInfo>) -> Self {
Self { Self {
op_id: intf::get_random_u64(), op_id: intf::get_random_u64(),
sender_info,
kind: RPCOperationKind::Statement(statement), kind: RPCOperationKind::Statement(statement),
} }
} }
pub fn new_answer(request: &RPCOperation, answer: RPCAnswer) -> Self { pub fn new_answer(
request: &RPCOperation,
answer: RPCAnswer,
sender_info: Option<SignedNodeInfo>,
) -> Self {
Self { Self {
op_id: request.op_id, op_id: request.op_id,
sender_info,
kind: RPCOperationKind::Answer(answer), kind: RPCOperationKind::Answer(answer),
} }
} }
@ -86,6 +94,10 @@ impl RPCOperation {
self.op_id self.op_id
} }
pub fn sender_info(&self) -> Option<&SignedNodeInfo> {
self.sender_info.as_ref()
}
pub fn kind(&self) -> &RPCOperationKind { pub fn kind(&self) -> &RPCOperationKind {
&self.kind &self.kind
} }
@ -100,16 +112,32 @@ impl RPCOperation {
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
let op_id = operation_reader.get_op_id(); let op_id = operation_reader.get_op_id();
let sender_info = if operation_reader.has_sender_info() {
let sni_reader = operation_reader.get_sender_info();
let sni = decode_signed_node_info(&sni_reader, sender_node_id, true)?;
Some(sni)
} else {
None
};
let kind_reader = operation_reader.get_kind(); let kind_reader = operation_reader.get_kind();
let kind = RPCOperationKind::decode(&kind_reader, sender_node_id)?; let kind = RPCOperationKind::decode(&kind_reader, sender_node_id)?;
Ok(RPCOperation { op_id, kind }) Ok(RPCOperation {
op_id,
sender_info,
kind,
})
} }
pub fn encode(&self, builder: &mut veilid_capnp::operation::Builder) -> Result<(), RPCError> { pub fn encode(&self, builder: &mut veilid_capnp::operation::Builder) -> Result<(), RPCError> {
builder.set_op_id(self.op_id); builder.set_op_id(self.op_id);
let mut k_builder = builder.reborrow().init_kind(); let mut k_builder = builder.reborrow().init_kind();
self.kind.encode(&mut k_builder)?; self.kind.encode(&mut k_builder)?;
if let Some(sender_info) = self.sender_info {
let si_builder = builder.reborrow().init_sender_info();
encode_signed_node_info(&self.sender_info, &mut si_builder)?;
}
Ok(()) Ok(())
} }
} }

View File

@ -18,12 +18,6 @@ impl RPCQuestion {
pub fn detail(&self) -> &RPCQuestionDetail { pub fn detail(&self) -> &RPCQuestionDetail {
&self.detail &self.detail
} }
// pub fn into_detail(self) -> RPCQuestionDetail {
// self.detail
// }
// pub fn into_respond_to_detail(self) -> (RespondTo, RPCQuestionDetail) {
// (self.respond_to, self.detail)
// }
pub fn desc(&self) -> &'static str { pub fn desc(&self) -> &'static str {
self.detail.desc() self.detail.desc()
} }
@ -32,7 +26,7 @@ impl RPCQuestion {
sender_node_id: &DHTKey, sender_node_id: &DHTKey,
) -> Result<RPCQuestion, RPCError> { ) -> Result<RPCQuestion, RPCError> {
let rt_reader = reader.get_respond_to(); let rt_reader = reader.get_respond_to();
let respond_to = RespondTo::decode(&rt_reader, sender_node_id)?; let respond_to = RespondTo::decode(&rt_reader)?;
let d_reader = reader.get_detail(); let d_reader = reader.get_detail();
let detail = RPCQuestionDetail::decode(&d_reader)?; let detail = RPCQuestionDetail::decode(&d_reader)?;
Ok(RPCQuestion { respond_to, detail }) Ok(RPCQuestion { respond_to, detail })

View File

@ -3,7 +3,7 @@ use rpc_processor::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum RespondTo { pub enum RespondTo {
Sender(Option<SignedNodeInfo>), Sender,
PrivateRoute(PrivateRoute), PrivateRoute(PrivateRoute),
} }
@ -13,11 +13,7 @@ impl RespondTo {
builder: &mut veilid_capnp::question::respond_to::Builder, builder: &mut veilid_capnp::question::respond_to::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
match self { match self {
Self::Sender(Some(sni)) => { Self::Sender => {
let mut sni_builder = builder.reborrow().init_sender_with_info();
encode_signed_node_info(sni, &mut sni_builder)?;
}
Self::Sender(None) => {
builder.reborrow().set_sender(()); builder.reborrow().set_sender(());
} }
Self::PrivateRoute(pr) => { Self::PrivateRoute(pr) => {
@ -28,17 +24,9 @@ impl RespondTo {
Ok(()) Ok(())
} }
pub fn decode( pub fn decode(reader: &veilid_capnp::question::respond_to::Reader) -> Result<Self, RPCError> {
reader: &veilid_capnp::question::respond_to::Reader,
sender_node_id: &DHTKey,
) -> Result<Self, RPCError> {
let respond_to = match reader.which().map_err(RPCError::protocol)? { let respond_to = match reader.which().map_err(RPCError::protocol)? {
veilid_capnp::question::respond_to::Sender(()) => RespondTo::Sender(None), veilid_capnp::question::respond_to::Sender(()) => RespondTo::Sender,
veilid_capnp::question::respond_to::SenderWithInfo(sender_ni_reader) => {
let sender_ni_reader = sender_ni_reader.map_err(RPCError::protocol)?;
let sni = decode_signed_node_info(&sender_ni_reader, sender_node_id, true)?;
RespondTo::Sender(Some(sni))
}
veilid_capnp::question::respond_to::PrivateRoute(pr_reader) => { veilid_capnp::question::respond_to::PrivateRoute(pr_reader) => {
let pr_reader = pr_reader.map_err(RPCError::protocol)?; let pr_reader = pr_reader.map_err(RPCError::protocol)?;
let pr = decode_private_route(&pr_reader)?; let pr = decode_private_route(&pr_reader)?;

View File

@ -0,0 +1,135 @@
use super::*;
/// Where to send an RPC message
#[derive(Debug, Clone)]
pub enum Destination {
/// Send to node directly
Direct {
/// The node to send to
target: NodeRef,
/// An optional safety route specification to send from for sender privacy
safety_route_spec: Option<Arc<SafetyRouteSpec>>,
},
/// Send to node for relay purposes
Relay {
/// The relay to send to
relay: NodeRef,
/// The final destination the relay should send to
target: DHTKey,
/// An optional safety route specification to send from for sender privacy
safety_route_spec: Option<Arc<SafetyRouteSpec>>,
},
/// Send to private route (privateroute)
PrivateRoute {
/// A private route to send to
private_route: PrivateRoute,
/// An optional safety route specification to send from for sender privacy
safety_route_spec: Option<Arc<SafetyRouteSpec>>,
},
}
impl Destination {
pub fn direct(target: NodeRef) -> Self {
Self::Direct {
target,
safety_route_spec: None,
}
}
pub fn relay(relay: NodeRef, target: DHTKey) -> Self {
Self::Relay {
relay,
target,
safety_route_spec: None,
}
}
pub fn private_route(private_route: PrivateRoute) -> Self {
Self::PrivateRoute {
private_route,
safety_route_spec: None,
}
}
pub fn safety_route_spec(&self) -> Option<Arc<SafetyRouteSpec>> {
match self {
Destination::Direct {
target,
safety_route_spec,
} => safety_route_spec.clone(),
Destination::Relay {
relay,
target,
safety_route_spec,
} => safety_route_spec.clone(),
Destination::PrivateRoute {
private_route,
safety_route_spec,
} => safety_route_spec.clone(),
}
}
pub fn with_safety_route_spec(self, safety_route_spec: Arc<SafetyRouteSpec>) -> Self {
match self {
Destination::Direct {
target,
safety_route_spec: _,
} => Self::Direct {
target,
safety_route_spec: Some(safety_route_spec),
},
Destination::Relay {
relay,
target,
safety_route_spec: _,
} => Self::Relay {
relay,
target,
safety_route_spec: Some(safety_route_spec),
},
Destination::PrivateRoute {
private_route,
safety_route_spec: _,
} => Self::PrivateRoute {
private_route,
safety_route_spec: Some(safety_route_spec),
},
}
}
}
impl fmt::Display for Destination {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Destination::Direct {
target,
routing_domain,
safety_route_spec,
} => {
let sr = safety_route_spec
.map(|_sr| "+SR".to_owned())
.unwrap_or_default();
write!(f, "{:?}{}", target, sr)
}
Destination::Relay {
relay,
target,
safety_route_spec,
} => {
let sr = safety_route_spec
.map(|_sr| "+SR".to_owned())
.unwrap_or_default();
write!(f, "{:?}@{:?}{}", target.encode(), relay, sr)
}
Destination::PrivateRoute {
private_route,
safety_route_spec,
} => {
let sr = safety_route_spec
.map(|_sr| "+SR".to_owned())
.unwrap_or_default();
write!(f, "{}{}", private_route, sr)
}
}
}
}

View File

@ -1,4 +1,5 @@
mod coders; mod coders;
mod destination;
mod private_route; mod private_route;
mod rpc_cancel_tunnel; mod rpc_cancel_tunnel;
mod rpc_complete_tunnel; mod rpc_complete_tunnel;
@ -18,6 +19,7 @@ mod rpc_validate_dial_info;
mod rpc_value_changed; mod rpc_value_changed;
mod rpc_watch_value; mod rpc_watch_value;
pub use destination::*;
pub use private_route::*; pub use private_route::*;
pub use rpc_error::*; pub use rpc_error::*;
@ -36,208 +38,6 @@ use stop_token::future::FutureExt;
type OperationId = u64; type OperationId = u64;
/// Where to send an RPC message
#[derive(Debug, Clone)]
pub enum Destination {
/// Send to node directly
Direct {
/// The node to send to
target: NodeRef,
/// An optional routing domain to require
routing_domain: Option<RoutingDomain>,
/// An optional safety route specification to send from for sender privacy
safety_route_spec: Option<Arc<SafetyRouteSpec>>,
},
/// Send to node for relay purposes
Relay {
/// The relay to send to
relay: NodeRef,
/// The final destination the relay should send to
target: DHTKey,
/// An optional routing domain to require
routing_domain: Option<RoutingDomain>,
/// An optional safety route specification to send from for sender privacy
safety_route_spec: Option<Arc<SafetyRouteSpec>>,
},
/// Send to private route (privateroute)
PrivateRoute {
/// A private route to send to
private_route: PrivateRoute,
/// An optional safety route specification to send from for sender privacy
safety_route_spec: Option<Arc<SafetyRouteSpec>>,
},
}
impl Destination {
pub fn direct(target: NodeRef) -> Self {
Self::Direct {
target,
routing_domain: None,
safety_route_spec: None,
}
}
pub fn relay(relay: NodeRef, target: DHTKey) -> Self {
Self::Relay {
relay,
target,
routing_domain: None,
safety_route_spec: None,
}
}
pub fn private_route(private_route: PrivateRoute) -> Self {
Self::PrivateRoute {
private_route,
safety_route_spec: None,
}
}
pub fn
pub fn routing_domain(&self) -> Option<RoutingDomain> {
match self {
Destination::Direct {
target,
routing_domain,
safety_route_spec,
} => *routing_domain,
Destination::Relay {
relay,
target,
routing_domain,
safety_route_spec,
} => *routing_domain,
Destination::PrivateRoute {
private_route,
safety_route_spec,
} => Some(RoutingDomain::PublicInternet),
}
}
pub fn safety_route_spec(&self) -> Option<Arc<SafetyRouteSpec>> {
match self {
Destination::Direct {
target,
routing_domain,
safety_route_spec,
} => safety_route_spec.clone(),
Destination::Relay {
relay,
target,
routing_domain,
safety_route_spec,
} => safety_route_spec.clone(),
Destination::PrivateRoute {
private_route,
safety_route_spec,
} => safety_route_spec.clone(),
}
}
pub fn with_routing_domain(self, routing_domain: RoutingDomain) -> Self {
match self {
Destination::Direct {
target,
routing_domain: _,
safety_route_spec,
} => Self::Direct {
target,
routing_domain: Some(routing_domain),
safety_route_spec,
},
Destination::Relay {
relay,
target,
routing_domain: _,
safety_route_spec,
} => Self::Relay {
relay,
target,
routing_domain: Some(routing_domain),
safety_route_spec,
},
Destination::PrivateRoute {
private_route: _,
safety_route_spec: _,
} => panic!("Private route is only valid in PublicInternet routing domain"),
}
}
pub fn with_safety_route_spec(self, safety_route_spec: Arc<SafetyRouteSpec>) -> Self {
match self {
Destination::Direct {
target,
routing_domain,
safety_route_spec: _,
} => Self::Direct {
target,
routing_domain,
safety_route_spec: Some(safety_route_spec),
},
Destination::Relay {
relay,
target,
routing_domain,
safety_route_spec: _,
} => Self::Relay {
relay,
target,
routing_domain,
safety_route_spec: Some(safety_route_spec),
},
Destination::PrivateRoute {
private_route,
safety_route_spec: _,
} => Self::PrivateRoute {
private_route,
safety_route_spec: Some(safety_route_spec),
},
}
}
}
impl fmt::Display for Destination {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Destination::Direct {
target,
routing_domain,
safety_route_spec,
} => {
let rd = routing_domain
.map(|rd| format!("#{:?}", rd))
.unwrap_or_default();
let sr = safety_route_spec
.map(|_sr| "+SR".to_owned())
.unwrap_or_default();
write!(f, "{:?}{}{}", target, rd, sr)
}
Destination::Relay {
relay,
target,
routing_domain,
safety_route_spec,
} => {
let rd = routing_domain
.map(|rd| format!("#{:?}", rd))
.unwrap_or_default();
let sr = safety_route_spec
.map(|_sr| "+SR".to_owned())
.unwrap_or_default();
write!(f, "{:?}@{:?}{}{}", target.encode(), relay, rd, sr)
}
Destination::PrivateRoute {
private_route,
safety_route_spec,
} => {
let sr = safety_route_spec
.map(|_sr| "+SR".to_owned())
.unwrap_or_default();
write!(f, "{}{}", private_route, sr)
}
}
}
}
/// The decoded header of an RPC message /// The decoded header of an RPC message
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct RPCMessageHeader { struct RPCMessageHeader {
@ -251,6 +51,8 @@ struct RPCMessageHeader {
peer_noderef: NodeRef, peer_noderef: NodeRef,
/// The connection from the peer sent the message (not the original sender) /// The connection from the peer sent the message (not the original sender)
connection_descriptor: ConnectionDescriptor, connection_descriptor: ConnectionDescriptor,
/// The routing domain the message was sent through
routing_domain: RoutingDomain,
} }
#[derive(Debug)] #[derive(Debug)]
@ -352,7 +154,6 @@ pub struct RPCProcessorInner {
pub struct RPCProcessor { pub struct RPCProcessor {
crypto: Crypto, crypto: Crypto,
config: VeilidConfig, config: VeilidConfig,
enable_local_peer_scope: bool,
inner: Arc<Mutex<RPCProcessorInner>>, inner: Arc<Mutex<RPCProcessorInner>>,
} }
@ -375,11 +176,6 @@ impl RPCProcessor {
Self { Self {
crypto: network_manager.crypto(), crypto: network_manager.crypto(),
config: network_manager.config(), config: network_manager.config(),
enable_local_peer_scope: network_manager
.config()
.get()
.network
.enable_local_peer_scope,
inner: Arc::new(Mutex::new(Self::new_inner(network_manager))), inner: Arc::new(Mutex::new(Self::new_inner(network_manager))),
} }
} }
@ -402,12 +198,8 @@ impl RPCProcessor {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
fn filter_peer_scope(&self, node_info: &NodeInfo) -> bool { /// Determine if a NodeInfo can be placed into the specified routing domain
// if local peer scope is enabled, then don't reject any peer info fn filter_node_info(&self, routing_domain: RoutingDomain, node_info: &NodeInfo) -> bool {
if self.enable_local_peer_scope {
return true;
}
// reject attempts to include non-public addresses in results // reject attempts to include non-public addresses in results
for did in &node_info.dial_info_detail_list { for did in &node_info.dial_info_detail_list {
if !did.dial_info.is_global() { if !did.dial_info.is_global() {
@ -584,31 +376,6 @@ impl RPCProcessor {
out out
} }
/// Gets a 'RespondTo::Sender' that contains either our dial info,
/// or None if the peer has seen our dial info before or our node info is not yet valid
/// because of an unknown network class
pub fn make_respond_to_sender(
&self,
routing_domain: RoutingDomain,
peer: NodeRef,
) -> RespondTo {
if peer.has_seen_our_node_info(routing_domain)
|| matches!(
self.network_manager()
.get_network_class(routing_domain)
.unwrap_or(NetworkClass::Invalid),
NetworkClass::Invalid
)
{
RespondTo::Sender(None)
} else {
let our_sni = self
.routing_table()
.get_own_signed_node_info(routing_domain);
RespondTo::Sender(Some(our_sni))
}
}
/// Produce a byte buffer that represents the wire encoding of the entire /// Produce a byte buffer that represents the wire encoding of the entire
/// unencrypted envelope body for a RPC message. This incorporates /// unencrypted envelope body for a RPC message. This incorporates
/// wrapping a private and/or safety route if they are specified. /// wrapping a private and/or safety route if they are specified.
@ -617,7 +384,7 @@ impl RPCProcessor {
&self, &self,
dest: Destination, dest: Destination,
operation: &RPCOperation, operation: &RPCOperation,
) -> Result<RenderedOperation, RPCError> { xxx continue propagating safetyroutespec ) -> Result<RenderedOperation, RPCError> {
let out_node_id; // Envelope Node Id let out_node_id; // Envelope Node Id
let mut out_node_ref: Option<NodeRef> = None; // Node to send envelope to let mut out_node_ref: Option<NodeRef> = None; // Node to send envelope to
let out_hop_count: usize; // Total safety + private route hop count let out_hop_count: usize; // Total safety + private route hop count
@ -634,12 +401,28 @@ impl RPCProcessor {
// To where are we sending the request // To where are we sending the request
match dest { match dest {
Destination::Direct(ref node_ref) | Destination::Relay(ref node_ref, _) => { Destination::Direct {
target: node_ref,
routing_domain,
safety_route_spec,
}
| Destination::Relay {
relay: node_ref,
target: _,
routing_domain,
safety_route_spec,
} => {
// Send to a node without a private route // Send to a node without a private route
// -------------------------------------- // --------------------------------------
// Get the actual destination node id accounting for relays // Get the actual destination node id accounting for relays
let (node_ref, node_id) = if let Destination::Relay(_, dht_key) = dest { let (node_ref, node_id) = if let Destination::Relay {
relay: _,
target: dht_key,
routing_domain: _,
safety_route_spec: _,
} = dest
{
(node_ref.clone(), dht_key.clone()) (node_ref.clone(), dht_key.clone())
} else { } else {
let node_id = node_ref.node_id(); let node_id = node_ref.node_id();
@ -676,7 +459,10 @@ impl RPCProcessor {
} }
}; };
} }
Destination::PrivateRoute(private_route) => { Destination::PrivateRoute {
private_route,
safety_route_spec,
} => {
// Send to private route // Send to private route
// --------------------- // ---------------------
// Reply with 'route' operation // Reply with 'route' operation
@ -723,12 +509,22 @@ impl RPCProcessor {
} }
// Issue a question over the network, possibly using an anonymized route // Issue a question over the network, possibly using an anonymized route
#[instrument(level = "debug", skip(self, question, safety_route_spec), err)] #[instrument(level = "debug", skip(self, question), err)]
async fn question( async fn question(
&self, &self,
dest: Destination, dest: Destination,
question: RPCQuestion, question: RPCQuestion,
) -> Result<NetworkResult<WaitableReply>, RPCError> { ) -> Result<NetworkResult<WaitableReply>, RPCError> {
// Get sender info if we should send that
let opt_sender_info = if dest.safety_route_spec().is_none() && matches!(question.respond_to(), RespondTo::Sender) {
// Sender is not private, send sender info if needed
// Get the noderef of the eventual destination or first route hop
if let Some(target_nr) = self.routing_table().lookup_node_ref(dest.get_target_id()) {
if target_nr.has_seen_our_node_info(R)
}
}
// Wrap question in operation // Wrap question in operation
let operation = RPCOperation::new_question(question); let operation = RPCOperation::new_question(question);
let op_id = operation.op_id(); let op_id = operation.op_id();
@ -951,6 +747,10 @@ impl RPCProcessor {
&self, &self,
encoded_msg: RPCMessageEncoded, encoded_msg: RPCMessageEncoded,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
// Get the routing domain
let routing_domain = encoded_msg.header.routing_domain;
// Decode the operation // Decode the operation
let sender_node_id = encoded_msg.header.envelope.get_sender_id(); let sender_node_id = encoded_msg.header.envelope.get_sender_id();
@ -971,12 +771,13 @@ impl RPCProcessor {
match q.respond_to() { match q.respond_to() {
RespondTo::Sender(Some(sender_ni)) => { RespondTo::Sender(Some(sender_ni)) => {
// Sender NodeInfo was specified, update our routing table with it // Sender NodeInfo was specified, update our routing table with it
if !self.filter_peer_scope(&sender_ni.node_info) { if !self.filter_node_info(&sender_ni.node_info) {
return Err(RPCError::invalid_format( return Err(RPCError::invalid_format(
"respond_to_sender_signed_node_info has invalid peer scope", "respond_to_sender_signed_node_info has invalid peer scope",
)); ));
} }
opt_sender_nr = self.routing_table().register_node_with_signed_node_info( opt_sender_nr = self.routing_table().register_node_with_signed_node_info(
routing_domain,
sender_node_id, sender_node_id,
sender_ni.clone(), sender_ni.clone(),
false, false,
@ -1168,6 +969,7 @@ impl RPCProcessor {
body: Vec<u8>, body: Vec<u8>,
peer_noderef: NodeRef, peer_noderef: NodeRef,
connection_descriptor: ConnectionDescriptor, connection_descriptor: ConnectionDescriptor,
routing_domain: RoutingDomain,
) -> EyreResult<()> { ) -> EyreResult<()> {
let msg = RPCMessageEncoded { let msg = RPCMessageEncoded {
header: RPCMessageHeader { header: RPCMessageHeader {
@ -1176,6 +978,7 @@ impl RPCProcessor {
body_len: body.len() as u64, body_len: body.len() as u64,
peer_noderef, peer_noderef,
connection_descriptor, connection_descriptor,
routing_domain,
}, },
data: RPCMessageData { contents: body }, data: RPCMessageData { contents: body },
}; };

View File

@ -4,7 +4,7 @@ impl RPCProcessor {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
fn compile_safety_route( fn compile_safety_route(
&self, &self,
safety_route_spec: &SafetyRouteSpec, safety_route_spec: Arc<SafetyRouteSpec>,
private_route: PrivateRoute, private_route: PrivateRoute,
) -> Result<SafetyRoute, RPCError> { ) -> Result<SafetyRoute, RPCError> {
// Ensure the total hop count isn't too long for our config // Ensure the total hop count isn't too long for our config
@ -111,15 +111,15 @@ impl RPCProcessor {
// Wrap an operation inside a route // Wrap an operation inside a route
pub(super) fn wrap_with_route( pub(super) fn wrap_with_route(
&self, &self,
safety_route_spec: Option<&SafetyRouteSpec>, safety_route_spec: Option<Arc<SafetyRouteSpec>>,
private_route: PrivateRoute, private_route: PrivateRoute,
message_data: Vec<u8>, message_data: Vec<u8>,
) -> Result<Vec<u8>, RPCError> { ) -> Result<Vec<u8>, RPCError> {
// Encrypt routed operation // Encrypt routed operation
// Xmsg + ENC(Xmsg, DH(PKapr, SKbsr)) // Xmsg + ENC(Xmsg, DH(PKapr, SKbsr))
let nonce = Crypto::get_random_nonce(); let nonce = Crypto::get_random_nonce();
let stub_safety_route_spec = SafetyRouteSpec::new(); let safety_route_spec =
let safety_route_spec = safety_route_spec.unwrap_or(&stub_safety_route_spec); safety_route_spec.unwrap_or_else(|| Arc::new(SafetyRouteSpec::new()));
let dh_secret = self let dh_secret = self
.crypto .crypto
.cached_dh(&private_route.public_key, &safety_route_spec.secret_key) .cached_dh(&private_route.public_key, &safety_route_spec.secret_key)

View File

@ -8,15 +8,11 @@ impl RPCProcessor {
self, self,
dest: Destination, dest: Destination,
key: DHTKey, key: DHTKey,
safety_route: Option<&SafetyRouteSpec>,
respond_to: RespondTo,
) -> Result<NetworkResult<Answer<Vec<PeerInfo>>>, RPCError> { ) -> Result<NetworkResult<Answer<Vec<PeerInfo>>>, RPCError> {
let find_node_q = RPCOperationFindNodeQ { node_id: key }; let find_node_q = RPCQuestionDetail::FindNodeQ(RPCOperationFindNodeQ { node_id: key });
let question = RPCQuestion::new(respond_to, RPCQuestionDetail::FindNodeQ(find_node_q));
// Send the find_node request // Send the find_node request
let waitable_reply = let waitable_reply = network_result_try!(self.question(dest, find_node_q).await?);
network_result_try!(self.question(dest, question, safety_route).await?);
// Wait for reply // Wait for reply
let (msg, latency) = match self.wait_for_reply(waitable_reply).await? { let (msg, latency) = match self.wait_for_reply(waitable_reply).await? {
@ -35,7 +31,7 @@ impl RPCProcessor {
// Verify peers are in the correct peer scope // Verify peers are in the correct peer scope
for peer_info in &find_node_a.peers { for peer_info in &find_node_a.peers {
if !self.filter_peer_scope(&peer_info.signed_node_info.node_info) { if !self.filter_node_info(&peer_info.signed_node_info.node_info) {
return Err(RPCError::invalid_format( return Err(RPCError::invalid_format(
"find_node response has invalid peer scope", "find_node response has invalid peer scope",
)); ));

View File

@ -2,20 +2,20 @@ use super::*;
impl RPCProcessor { impl RPCProcessor {
// Sends a our node info to another node // Sends a our node info to another node
// Can be sent via all methods including relays and routes
#[instrument(level = "trace", skip(self), ret, err)] #[instrument(level = "trace", skip(self), ret, err)]
pub async fn rpc_call_node_info_update( pub async fn rpc_call_node_info_update(
self, self,
target: NodeRef, target: NodeRef,
routing_domain: RoutingDomain, routing_domain: RoutingDomain,
) -> Result<NetworkResult<()>, RPCError> { ) -> Result<NetworkResult<()>, RPCError> {
// Get the signed node info for the desired routing domain to send update with
let signed_node_info = self let signed_node_info = self
.routing_table() .routing_table()
.get_own_signed_node_info(routing_domain); .get_own_signed_node_info(routing_domain);
let node_info_update = RPCOperationNodeInfoUpdate { signed_node_info }; let node_info_update = RPCOperationNodeInfoUpdate { signed_node_info };
let statement = RPCStatement::new(RPCStatementDetail::NodeInfoUpdate(node_info_update)); let statement = RPCStatement::new(RPCStatementDetail::NodeInfoUpdate(node_info_update));
// Send the node_info_update request // Send the node_info_update request to the specific routing domain requested
network_result_try!( network_result_try!(
self.statement( self.statement(
Destination::direct(target).with_routing_domain(routing_domain), Destination::direct(target).with_routing_domain(routing_domain),
@ -41,7 +41,7 @@ impl RPCProcessor {
}; };
// Update our routing table with signed node info // Update our routing table with signed node info
if !self.filter_peer_scope(&node_info_update.signed_node_info.node_info) { if !self.filter_node_info(&node_info_update.signed_node_info.node_info) {
log_rpc!(debug log_rpc!(debug
"node_info_update has invalid peer scope from {}", sender_node_id "node_info_update has invalid peer scope from {}", sender_node_id
); );

View File

@ -8,14 +8,21 @@ impl RPCProcessor {
self, self,
peer: NodeRef, peer: NodeRef,
) -> Result<NetworkResult<Answer<SenderInfo>>, RPCError> { ) -> Result<NetworkResult<Answer<SenderInfo>>, RPCError> {
let node_status = self.network_manager().generate_node_status(); let routing_domain = match peer.best_routing_domain() {
Some(rd) => rd,
None => {
return Ok(NetworkResult::no_connection_other(
"no routing domain for peer",
))
}
};
let node_status = self.network_manager().generate_node_status(routing_domain);
let status_q = RPCOperationStatusQ { node_status }; let status_q = RPCOperationStatusQ { node_status };
let respond_to = self.make_respond_to_sender(peer.clone()); let question = RPCQuestion::new(RespondTo::Sender, RPCQuestionDetail::StatusQ(status_q));
let question = RPCQuestion::new(respond_to, RPCQuestionDetail::StatusQ(status_q));
// Send the info request // Send the info request
let waitable_reply = network_result_try!( let waitable_reply = network_result_try!(
self.question(Destination::Direct(peer.clone()), question, None) self.question(Destination::direct(peer.clone()), question)
.await? .await?
); );
@ -37,26 +44,48 @@ impl RPCProcessor {
_ => return Err(RPCError::invalid_format("not an answer")), _ => return Err(RPCError::invalid_format("not an answer")),
}; };
// Ensure the returned node status is the kind for the routing domain we asked for
match routing_domain {
RoutingDomain::PublicInternet => {
if !matches!(status_a.node_status, NodeStatus::PublicInternet(_)) {
return Ok(NetworkResult::invalid_message(
"node status doesn't match PublicInternet routing domain",
));
}
}
RoutingDomain::LocalNetwork => {
if !matches!(status_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 // Update latest node status in routing table
peer.update_node_status(status_a.node_status.clone()); peer.update_node_status(status_a.node_status);
// Report sender_info IP addresses to network manager // Report sender_info IP addresses to network manager
// Don't need to validate these addresses for the current routing domain
// the address itself is irrelevant, and the remote node can lie anyway
if let Some(socket_address) = status_a.sender_info.socket_address { if let Some(socket_address) = status_a.sender_info.socket_address {
match send_data_kind { match send_data_kind {
SendDataKind::Direct(connection_descriptor) => { SendDataKind::Direct(connection_descriptor) => match routing_domain {
match connection_descriptor.peer_scope() { RoutingDomain::PublicInternet => self
PeerScope::Global => self.network_manager().report_global_socket_address( .network_manager()
.report_public_internet_socket_address(
socket_address, socket_address,
connection_descriptor, connection_descriptor,
peer, peer,
), ),
PeerScope::Local => self.network_manager().report_local_socket_address( RoutingDomain::LocalNetwork => {
self.network_manager().report_local_network_socket_address(
socket_address, socket_address,
connection_descriptor, connection_descriptor,
peer, peer,
), )
} }
} },
SendDataKind::Indirect => { SendDataKind::Indirect => {
// Do nothing in this case, as the socket address returned here would be for any node other than ours // Do nothing in this case, as the socket address returned here would be for any node other than ours
} }
@ -75,6 +104,7 @@ impl RPCProcessor {
#[instrument(level = "trace", skip(self, msg), fields(msg.operation.op_id, res), err)] #[instrument(level = "trace", skip(self, msg), fields(msg.operation.op_id, res), err)]
pub(crate) async fn process_status_q(&self, msg: RPCMessage) -> Result<(), RPCError> { pub(crate) async fn process_status_q(&self, msg: RPCMessage) -> Result<(), RPCError> {
let connection_descriptor = msg.header.connection_descriptor; let connection_descriptor = msg.header.connection_descriptor;
let routing_domain = msg.header.routing_domain;
// Get the question // Get the question
let status_q = match msg.operation.kind() { let status_q = match msg.operation.kind() {
@ -85,6 +115,24 @@ impl RPCProcessor {
_ => panic!("not a question"), _ => panic!("not a question"),
}; };
// Ensure the node status from the question is the kind for the routing domain we received the request in
match routing_domain {
RoutingDomain::PublicInternet => {
if !matches!(status_a.node_status, NodeStatus::PublicInternet(_)) {
return Ok(NetworkResult::invalid_message(
"node status doesn't match PublicInternet routing domain",
));
}
}
RoutingDomain::LocalNetwork => {
if !matches!(status_a.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 // update node status for the requesting node to our routing table
if let Some(sender_nr) = msg.opt_sender_nr.clone() { if let Some(sender_nr) = msg.opt_sender_nr.clone() {
// Update latest node status in routing table for the statusq sender // Update latest node status in routing table for the statusq sender
@ -92,7 +140,7 @@ impl RPCProcessor {
} }
// Make status answer // Make status answer
let node_status = self.network_manager().generate_node_status(); let node_status = self.network_manager().generate_node_status(routing_domain);
// Get the peer address in the returned sender info // Get the peer address in the returned sender info
let sender_info = SenderInfo { let sender_info = SenderInfo {
@ -106,11 +154,7 @@ impl RPCProcessor {
// Send status answer // Send status answer
let res = self let res = self
.answer( .answer(msg, RPCAnswer::new(RPCAnswerDetail::StatusA(status_a)))
msg,
RPCAnswer::new(RPCAnswerDetail::StatusA(status_a)),
None,
)
.await?; .await?;
tracing::Span::current().record("res", &tracing::field::display(res)); tracing::Span::current().record("res", &tracing::field::display(res));
Ok(()) Ok(())

View File

@ -224,7 +224,6 @@ fn config_callback(key: String) -> ConfigCallbackReturn {
"network.upnp" => Ok(Box::new(false)), "network.upnp" => Ok(Box::new(false)),
"network.natpmp" => Ok(Box::new(false)), "network.natpmp" => Ok(Box::new(false)),
"network.detect_address_changes" => Ok(Box::new(true)), "network.detect_address_changes" => Ok(Box::new(true)),
"network.enable_local_peer_scope" => Ok(Box::new(false)),
"network.restricted_nat_retries" => Ok(Box::new(3u32)), "network.restricted_nat_retries" => Ok(Box::new(3u32)),
"network.tls.certificate_path" => Ok(Box::new(get_certfile_path())), "network.tls.certificate_path" => Ok(Box::new(get_certfile_path())),
"network.tls.private_key_path" => Ok(Box::new(get_keyfile_path())), "network.tls.private_key_path" => Ok(Box::new(get_keyfile_path())),
@ -354,7 +353,6 @@ pub async fn test_config() {
assert_eq!(inner.network.upnp, false); assert_eq!(inner.network.upnp, false);
assert_eq!(inner.network.natpmp, false); assert_eq!(inner.network.natpmp, false);
assert_eq!(inner.network.detect_address_changes, true); assert_eq!(inner.network.detect_address_changes, true);
assert_eq!(inner.network.enable_local_peer_scope, false);
assert_eq!(inner.network.restricted_nat_retries, 3u32); assert_eq!(inner.network.restricted_nat_retries, 3u32);
assert_eq!(inner.network.tls.certificate_path, get_certfile_path()); assert_eq!(inner.network.tls.certificate_path, get_certfile_path());
assert_eq!(inner.network.tls.private_key_path, get_keyfile_path()); assert_eq!(inner.network.tls.private_key_path, get_keyfile_path());

View File

@ -45,6 +45,16 @@ fn get_address_type(text: &str) -> Option<AddressType> {
None None
} }
} }
fn get_routing_domain(text: &str) -> Option<RoutingDomain> {
let lctext = text.to_ascii_lowercase();
if "publicinternet".starts_with(&lctext) {
Some(RoutingDomain::PublicInternet)
} else if "localnetwork".starts_with(&lctext) {
Some(RoutingDomain::LocalNetwork)
} else {
None
}
}
fn get_debug_argument<T, G: FnOnce(&str) -> Option<T>>( fn get_debug_argument<T, G: FnOnce(&str) -> Option<T>>(
value: &str, value: &str,
@ -331,27 +341,40 @@ impl VeilidAPI {
None => return Ok("Node id not found in routing table".to_owned()), None => return Ok("Node id not found in routing table".to_owned()),
}; };
if args.len() >= 2 { let mut ai = 1;
let pt = let mut routing_domain = None;
get_debug_argument_at(&args, 1, "debug_ping", "protocol_type", get_protocol_type)?; while ai < args.len() {
nr.merge_filter(DialInfoFilter::all().with_protocol_type(pt)); if let Ok(pt) =
if args.len() >= 3 { get_debug_argument_at(&args, ai, "debug_ping", "protocol_type", get_protocol_type)
let at = get_debug_argument_at( {
&args, nr.merge_filter(DialInfoFilter::all().with_protocol_type(pt));
2, } else if let Ok(at) =
"debug_ping", get_debug_argument_at(&args, ai, "debug_ping", "address_type", get_address_type)
"address_type", {
get_address_type,
)?;
nr.merge_filter(DialInfoFilter::all().with_address_type(at)); nr.merge_filter(DialInfoFilter::all().with_address_type(at));
} else if let Ok(rd) = get_debug_argument_at(
&args,
ai,
"debug_ping",
"routing_domain",
get_routing_domain,
) {
if routing_domain.is_none() {
routing_domain = Some(rd);
} else {
return Ok("Multiple routing domains specified".to_owned());
}
} else {
return Ok(format!("Invalid argument specified: {}", args[ai]));
} }
ai += 1;
} }
let rpc = self.network_manager()?.rpc_processor(); let rpc = self.network_manager()?.rpc_processor();
// Dump routing table entry // Dump routing table entry
let out = match rpc let out = match rpc
.rpc_call_status(nr) .rpc_call_status(routing_domain, nr)
.await .await
.map_err(VeilidAPIError::internal)? .map_err(VeilidAPIError::internal)?
{ {
@ -383,7 +406,7 @@ impl VeilidAPI {
attach attach
detach detach
restart network restart network
ping <node_id> [protocol_type [address_type]] ping <node_id> [protocol_type][address_type][routing_domain]
contact <node_id> [protocol_type [address_type]] contact <node_id> [protocol_type [address_type]]
"# "#
.to_owned()) .to_owned())

View File

@ -460,9 +460,31 @@ pub struct NodeInfo {
} }
impl NodeInfo { impl NodeInfo {
pub fn is_valid(&self) -> bool { pub fn is_valid_in_routing_domain(
!matches!(self.network_class, NetworkClass::Invalid) &self,
routing_table: RoutingTable,
routing_domain: RoutingDomain,
) -> bool {
// Should not be passing around nodeinfo with an invalid network class
if matches!(self.network_class, NetworkClass::Invalid) {
return false;
}
// Ensure all of the dial info works in this routing domain
for did in self.dial_info_detail_list {
if !routing_table.ensure_dial_info_is_valid(routing_domain, &did.dial_info) {
return false;
}
}
// Ensure the relay is also valid in this routing domain if it is provided
if let Some(relay_peer_info) = self.relay_peer_info {
let relay_ni = &relay_peer_info.signed_node_info.node_info;
if !relay_ni.is_valid_in_routing_domain(routing_table, routing_domain) {
return false;
}
}
true
} }
pub fn first_filtered_dial_info_detail<F>(&self, filter: F) -> Option<DialInfoDetail> pub fn first_filtered_dial_info_detail<F>(&self, filter: F) -> Option<DialInfoDetail>
where where
F: Fn(&DialInfoDetail) -> bool, F: Fn(&DialInfoDetail) -> bool,
@ -783,7 +805,7 @@ impl FromStr for SocketAddress {
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct DialInfoFilter { pub struct DialInfoFilter {
pub protocol_type_set: ProtocolTypeSet, pub protocol_type_set: ProtocolTypeSet,
pub address_type_set: AddressTypeSet, pub address_type_set: AddressTypeSet,
@ -1096,6 +1118,14 @@ impl DialInfo {
pub fn address_type(&self) -> AddressType { pub fn address_type(&self) -> AddressType {
self.socket_address().address_type() self.socket_address().address_type()
} }
pub fn address(&self) -> Address {
match self {
Self::UDP(di) => di.socket_address.address,
Self::TCP(di) => di.socket_address.address,
Self::WS(di) => di.socket_address.address,
Self::WSS(di) => di.socket_address.address,
}
}
pub fn socket_address(&self) -> SocketAddress { pub fn socket_address(&self) -> SocketAddress {
match self { match self {
Self::UDP(di) => di.socket_address, Self::UDP(di) => di.socket_address,

View File

@ -137,7 +137,6 @@ pub struct VeilidConfigNetwork {
pub upnp: bool, pub upnp: bool,
pub natpmp: bool, pub natpmp: bool,
pub detect_address_changes: bool, pub detect_address_changes: bool,
pub enable_local_peer_scope: bool,
pub restricted_nat_retries: u32, pub restricted_nat_retries: u32,
pub tls: VeilidConfigTLS, pub tls: VeilidConfigTLS,
pub application: VeilidConfigApplication, pub application: VeilidConfigApplication,
@ -356,7 +355,6 @@ impl VeilidConfig {
get_config!(inner.network.upnp); get_config!(inner.network.upnp);
get_config!(inner.network.natpmp); get_config!(inner.network.natpmp);
get_config!(inner.network.detect_address_changes); get_config!(inner.network.detect_address_changes);
get_config!(inner.network.enable_local_peer_scope);
get_config!(inner.network.restricted_nat_retries); get_config!(inner.network.restricted_nat_retries);
get_config!(inner.network.tls.certificate_path); get_config!(inner.network.tls.certificate_path);
get_config!(inner.network.tls.private_key_path); get_config!(inner.network.tls.private_key_path);

View File

@ -215,3 +215,48 @@ pub fn ip_to_ipblock(ip6_prefix_size: usize, addr: IpAddr) -> IpAddr {
} }
} }
} }
pub fn ipaddr_apply_netmask(addr: IpAddr, netmask: IpAddr) -> IpAddr {
match addr {
IpAddr::V4(v4) => {
let v4mask = match netmask {
IpAddr::V4(v4mask) => v4mask,
IpAddr::V6(_) => {
panic!("netmask doesn't match ipv4 address");
}
};
let v4 = v4.octets();
let v4mask = v4mask.octets();
IpAddr::V4(Ipv4Addr::new(
v4[0] & v4mask[0],
v4[1] & v4mask[1],
v4[2] & v4mask[2],
v4[3] & v4mask[3],
))
}
IpAddr::V6(v6) => {
let v6mask = match netmask {
IpAddr::V4(_) => {
panic!("netmask doesn't match ipv6 address");
}
IpAddr::V6(v6mask) => v6mask,
};
let v6 = v6.segments();
let v6mask = v6mask.segments();
IpAddr::V6(Ipv6Addr::new(
v6[0] & v6mask[0],
v6[1] & v6mask[1],
v6[2] & v6mask[2],
v6[3] & v6mask[3],
v6[4] & v6mask[4],
v6[5] & v6mask[5],
v6[6] & v6mask[6],
v6[7] & v6mask[7],
))
}
}
}
pub fn ipaddr_in_network(addr: IpAddr, netaddr: IpAddr, netmask: IpAddr) -> bool {
ipaddr_apply_netmask(netaddr, netmask) == ipaddr_apply_netmask(addr, netmask)
}

View File

@ -85,7 +85,6 @@ Future<VeilidConfig> getDefaultVeilidConfig() async {
upnp: true, upnp: true,
natpmp: true, natpmp: true,
detectAddressChanges: true, detectAddressChanges: true,
enableLocalPeerScope: false,
restrictedNatRetries: 0, restrictedNatRetries: 0,
tls: VeilidConfigTLS( tls: VeilidConfigTLS(
certificatePath: "", certificatePath: "",

View File

@ -741,7 +741,6 @@ class VeilidConfigNetwork {
bool upnp; bool upnp;
bool natpmp; bool natpmp;
bool detectAddressChanges; bool detectAddressChanges;
bool enableLocalPeerScope;
int restrictedNatRetries; int restrictedNatRetries;
VeilidConfigTLS tls; VeilidConfigTLS tls;
VeilidConfigApplication application; VeilidConfigApplication application;
@ -767,7 +766,6 @@ class VeilidConfigNetwork {
required this.upnp, required this.upnp,
required this.natpmp, required this.natpmp,
required this.detectAddressChanges, required this.detectAddressChanges,
required this.enableLocalPeerScope,
required this.restrictedNatRetries, required this.restrictedNatRetries,
required this.tls, required this.tls,
required this.application, required this.application,
@ -795,7 +793,6 @@ class VeilidConfigNetwork {
'upnp': upnp, 'upnp': upnp,
'natpmp': natpmp, 'natpmp': natpmp,
'detect_address_changes': detectAddressChanges, 'detect_address_changes': detectAddressChanges,
'enable_local_peer_scope': enableLocalPeerScope,
'restricted_nat_retries': restrictedNatRetries, 'restricted_nat_retries': restrictedNatRetries,
'tls': tls.json, 'tls': tls.json,
'application': application.json, 'application': application.json,
@ -826,7 +823,6 @@ class VeilidConfigNetwork {
upnp = json['upnp'], upnp = json['upnp'],
natpmp = json['natpmp'], natpmp = json['natpmp'],
detectAddressChanges = json['detect_address_changes'], detectAddressChanges = json['detect_address_changes'],
enableLocalPeerScope = json['enable_local_peer_scope'],
restrictedNatRetries = json['restricted_nat_retries'], restrictedNatRetries = json['restricted_nat_retries'],
tls = VeilidConfigTLS.fromJson(json['tls']), tls = VeilidConfigTLS.fromJson(json['tls']),
application = VeilidConfigApplication.fromJson(json['application']), application = VeilidConfigApplication.fromJson(json['application']),

View File

@ -130,11 +130,7 @@ fn do_clap_matches(default_config_path: &OsStr) -> Result<clap::ArgMatches, clap
.value_name("BOOTSTRAP_NODE_LIST") .value_name("BOOTSTRAP_NODE_LIST")
.help("Specify a list of bootstrap node dialinfos to use"), .help("Specify a list of bootstrap node dialinfos to use"),
) )
.arg( ;
Arg::new("local")
.long("local")
.help("Enable local peer scope")
);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let matches = matches.arg( let matches = matches.arg(
@ -218,9 +214,6 @@ pub fn process_command_line() -> EyreResult<(Settings, ArgMatches)> {
if matches.is_present("attach") { if matches.is_present("attach") {
settingsrw.auto_attach = !matches!(matches.value_of("attach"), Some("true")); settingsrw.auto_attach = !matches!(matches.value_of("attach"), Some("true"));
} }
if matches.is_present("local") {
settingsrw.core.network.enable_local_peer_scope = true;
}
if matches.occurrences_of("delete-protected-store") != 0 { if matches.occurrences_of("delete-protected-store") != 0 {
settingsrw.core.protected_store.delete = true; settingsrw.core.protected_store.delete = true;
} }

View File

@ -99,7 +99,6 @@ core:
upnp: true upnp: true
natpmp: false natpmp: false
detect_address_changes: true detect_address_changes: true
enable_local_peer_scope: false
restricted_nat_retries: 0 restricted_nat_retries: 0
tls: tls:
certificate_path: '%CERTIFICATE_PATH%' certificate_path: '%CERTIFICATE_PATH%'
@ -589,7 +588,6 @@ pub struct Network {
pub upnp: bool, pub upnp: bool,
pub natpmp: bool, pub natpmp: bool,
pub detect_address_changes: bool, pub detect_address_changes: bool,
pub enable_local_peer_scope: bool,
pub restricted_nat_retries: u32, pub restricted_nat_retries: u32,
pub tls: Tls, pub tls: Tls,
pub application: Application, pub application: Application,
@ -976,7 +974,6 @@ impl Settings {
set_config_value!(inner.core.network.upnp, value); set_config_value!(inner.core.network.upnp, value);
set_config_value!(inner.core.network.natpmp, value); set_config_value!(inner.core.network.natpmp, value);
set_config_value!(inner.core.network.detect_address_changes, value); set_config_value!(inner.core.network.detect_address_changes, value);
set_config_value!(inner.core.network.enable_local_peer_scope, value);
set_config_value!(inner.core.network.restricted_nat_retries, value); set_config_value!(inner.core.network.restricted_nat_retries, value);
set_config_value!(inner.core.network.tls.certificate_path, value); set_config_value!(inner.core.network.tls.certificate_path, value);
set_config_value!(inner.core.network.tls.private_key_path, value); set_config_value!(inner.core.network.tls.private_key_path, value);
@ -1177,9 +1174,6 @@ impl Settings {
"network.detect_address_changes" => { "network.detect_address_changes" => {
Ok(Box::new(inner.core.network.detect_address_changes)) Ok(Box::new(inner.core.network.detect_address_changes))
} }
"network.enable_local_peer_scope" => {
Ok(Box::new(inner.core.network.enable_local_peer_scope))
}
"network.restricted_nat_retries" => { "network.restricted_nat_retries" => {
Ok(Box::new(inner.core.network.restricted_nat_retries)) Ok(Box::new(inner.core.network.restricted_nat_retries))
} }
@ -1503,7 +1497,6 @@ mod tests {
assert_eq!(s.core.network.upnp, true); assert_eq!(s.core.network.upnp, true);
assert_eq!(s.core.network.natpmp, false); assert_eq!(s.core.network.natpmp, false);
assert_eq!(s.core.network.detect_address_changes, true); assert_eq!(s.core.network.detect_address_changes, true);
assert_eq!(s.core.network.enable_local_peer_scope, false);
assert_eq!(s.core.network.restricted_nat_retries, 0u32); assert_eq!(s.core.network.restricted_nat_retries, 0u32);
// //
assert_eq!( assert_eq!(