refactor checkpoint

This commit is contained in:
John Smith 2022-09-04 14:17:28 -04:00
parent e0a5b1bd69
commit 79cda4a712
25 changed files with 531 additions and 398 deletions

View File

@ -491,7 +491,7 @@ 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. senderNodeInfo @1 :SignedNodeInfo; # (optional) SignedNodeInfo for the sender to be cached by the receiver.
kind :union { kind :union {
question @2 :Question; question @2 :Question;
statement @3 :Statement; statement @3 :Statement;

View File

@ -23,7 +23,7 @@ use connection_handle::*;
use connection_limits::*; use connection_limits::*;
use connection_manager::*; use connection_manager::*;
use dht::*; use dht::*;
use futures_util::stream::{FuturesUnordered, StreamExt}; use futures_util::stream::{FuturesOrdered, FuturesUnordered, StreamExt};
use hashlink::LruCache; use hashlink::LruCache;
use intf::*; use intf::*;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -388,22 +388,22 @@ impl NetworkManager {
.unwrap(); .unwrap();
inner.public_inbound_dial_info_filter = Some( inner.public_inbound_dial_info_filter = Some(
DialInfoFilter::global() DialInfoFilter::all()
.with_protocol_type_set(pc.inbound) .with_protocol_type_set(pc.inbound)
.with_address_type_set(pc.family_global), .with_address_type_set(pc.family_global),
); );
inner.local_inbound_dial_info_filter = Some( inner.local_inbound_dial_info_filter = Some(
DialInfoFilter::local() DialInfoFilter::all()
.with_protocol_type_set(pc.inbound) .with_protocol_type_set(pc.inbound)
.with_address_type_set(pc.family_local), .with_address_type_set(pc.family_local),
); );
inner.public_outbound_dial_info_filter = Some( inner.public_outbound_dial_info_filter = Some(
DialInfoFilter::global() DialInfoFilter::all()
.with_protocol_type_set(pc.outbound) .with_protocol_type_set(pc.outbound)
.with_address_type_set(pc.family_global), .with_address_type_set(pc.family_global),
); );
inner.local_outbound_dial_info_filter = Some( inner.local_outbound_dial_info_filter = Some(
DialInfoFilter::local() DialInfoFilter::all()
.with_protocol_type_set(pc.outbound) .with_protocol_type_set(pc.outbound)
.with_address_type_set(pc.family_local), .with_address_type_set(pc.family_local),
); );
@ -557,7 +557,7 @@ impl NetworkManager {
// See how many live PublicInternet entries we have // See how many live PublicInternet entries we have
let live_public_internet_entry_count = routing_table.get_entry_count( let live_public_internet_entry_count = routing_table.get_entry_count(
RoutingTableSet::only(RoutingTable::PublicInternet), RoutingDomain::PublicInternet.into(),
BucketEntryState::Unreliable, BucketEntryState::Unreliable,
); );
let min_peer_count = { let min_peer_count = {
@ -816,7 +816,7 @@ impl NetworkManager {
}; };
// Make a reverse connection to the peer and send the receipt to it // Make a reverse connection to the peer and send the receipt to it
rpc.rpc_call_return_receipt(Destination::Direct(peer_nr), None, receipt) rpc.rpc_call_return_receipt(Destination::direct(peer_nr), receipt)
.await .await
.wrap_err("rpc failure") .wrap_err("rpc failure")
} }
@ -841,12 +841,12 @@ impl NetworkManager {
}; };
// Get the udp direct dialinfo for the hole punch // Get the udp direct dialinfo for the hole punch
let outbound_dif = self let outbound_nrf = self
.get_outbound_dial_info_filter(RoutingDomain::PublicInternet) .get_outbound_node_ref_filter(RoutingDomain::PublicInternet)
.with_protocol_type(ProtocolType::UDP); .with_protocol_type(ProtocolType::UDP);
peer_nr.set_filter(Some(outbound_dif)); peer_nr.set_filter(Some(outbound_nrf));
let hole_punch_dial_info_detail = peer_nr let hole_punch_dial_info_detail = peer_nr
.first_filtered_dial_info_detail(Some(RoutingDomain::PublicInternet)) .first_filtered_dial_info_detail()
.ok_or_else(|| eyre!("No hole punch capable dialinfo found for node"))?; .ok_or_else(|| eyre!("No hole punch capable dialinfo found for node"))?;
// Now that we picked a specific dialinfo, further restrict the noderef to the specific address type // Now that we picked a specific dialinfo, further restrict the noderef to the specific address type
@ -872,7 +872,7 @@ impl NetworkManager {
peer_nr.set_last_connection(connection_descriptor, intf::get_timestamp()); peer_nr.set_last_connection(connection_descriptor, intf::get_timestamp());
// Return the receipt using the same dial info send the receipt to it // Return the receipt using the same dial info send the receipt to it
rpc.rpc_call_return_receipt(Destination::Direct(peer_nr), None, receipt) rpc.rpc_call_return_receipt(Destination::direct(peer_nr), receipt)
.await .await
.wrap_err("rpc failure") .wrap_err("rpc failure")
} }
@ -1014,7 +1014,7 @@ impl NetworkManager {
.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(
RoutingDomainSet::only(RoutingDomain::PublicInternet), RoutingDomain::PublicInternet.into(),
&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)
@ -1048,11 +1048,11 @@ impl NetworkManager {
.node_info_outbound_filter(RoutingDomain::PublicInternet), .node_info_outbound_filter(RoutingDomain::PublicInternet),
) )
.filtered( .filtered(
DialInfoFilter::global().with_protocol_type(ProtocolType::UDP), &DialInfoFilter::all().with_protocol_type(ProtocolType::UDP),
); );
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(
RoutingDomainSet::only(RoutingDomain::PublicInternet), RoutingDomain::PublicInternet.into(),
&inbound_udp_dif, &inbound_udp_dif,
) )
{ {
@ -1102,8 +1102,8 @@ impl NetworkManager {
#[instrument(level = "trace", skip(self), ret)] #[instrument(level = "trace", skip(self), ret)]
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_nrf = self.get_outbound_node_ref_filter(RoutingDomain::LocalNetwork);
let target_node_ref = target_node_ref.filtered_clone(NodeRefFilter::local_outbound_dif); let target_node_ref = target_node_ref.filtered_clone(local_outbound_nrf);
// Get the best matching local direct dial info if we have it // Get the best matching local direct dial info if we have it
if target_node_ref.is_filter_dead() { if target_node_ref.is_filter_dead() {
@ -1157,8 +1157,7 @@ impl NetworkManager {
let rpc = self.rpc_processor(); let rpc = self.rpc_processor();
network_result_try!(rpc network_result_try!(rpc
.rpc_call_signal( .rpc_call_signal(
Destination::Relay(relay_nr.clone(), target_nr.node_id()), Destination::relay(relay_nr, target_nr.node_id()),
None,
SignalInfo::ReverseConnect { receipt, peer_info }, SignalInfo::ReverseConnect { receipt, peer_info },
) )
.await .await
@ -1214,9 +1213,16 @@ impl NetworkManager {
data: Vec<u8>, data: Vec<u8>,
) -> EyreResult<NetworkResult<ConnectionDescriptor>> { ) -> EyreResult<NetworkResult<ConnectionDescriptor>> {
// Ensure we are filtered down to UDP (the only hole punch protocol supported today) // Ensure we are filtered down to UDP (the only hole punch protocol supported today)
// and only in the PublicInternet routing domain
assert!(target_nr assert!(target_nr
.filter_ref() .filter_ref()
.map(|dif| dif.protocol_type_set == ProtocolTypeSet::only(ProtocolType::UDP)) .map(|nrf| nrf.dial_info_filter.protocol_type_set
== ProtocolTypeSet::only(ProtocolType::UDP))
.unwrap_or_default());
assert!(target_nr
.filter_ref()
.map(|nrf| nrf.routing_domain_set
== RoutingDomainSet::only(RoutingDomain::PublicInternet))
.unwrap_or_default()); .unwrap_or_default());
// Build a return receipt for the signal // Build a return receipt for the signal
@ -1229,7 +1235,7 @@ impl NetworkManager {
// Get the udp direct dialinfo for the hole punch // Get the udp direct dialinfo for the hole punch
let hole_punch_did = target_nr let hole_punch_did = target_nr
.first_filtered_dial_info_detail(Some(RoutingDomain::PublicInternet)) .first_filtered_dial_info_detail()
.ok_or_else(|| eyre!("No hole punch capable dialinfo found for node"))?; .ok_or_else(|| eyre!("No hole punch capable dialinfo found for node"))?;
// Do our half of the hole punch by sending an empty packet // Do our half of the hole punch by sending an empty packet
@ -1246,8 +1252,7 @@ impl NetworkManager {
let rpc = self.rpc_processor(); let rpc = self.rpc_processor();
network_result_try!(rpc network_result_try!(rpc
.rpc_call_signal( .rpc_call_signal(
Destination::Relay(relay_nr.clone(), target_nr.node_id()), Destination::relay(relay_nr, target_nr.node_id()),
None,
SignalInfo::HolePunch { receipt, peer_info }, SignalInfo::HolePunch { receipt, peer_info },
) )
.await .await
@ -1394,7 +1399,7 @@ impl NetworkManager {
// Serialize out peer info // Serialize out peer info
let bootstrap_peerinfo: Vec<PeerInfo> = bootstrap_nodes let bootstrap_peerinfo: Vec<PeerInfo> = bootstrap_nodes
.iter() .iter()
.filter_map(|b| b.peer_info(RoutingDomain::PublicInternet)) .filter_map(|nr| nr.make_peer_info(RoutingDomain::PublicInternet))
.collect(); .collect();
let json_bytes = serialize_json(bootstrap_peerinfo).as_bytes().to_vec(); let json_bytes = serialize_json(bootstrap_peerinfo).as_bytes().to_vec();
@ -1484,7 +1489,7 @@ impl NetworkManager {
// Get the routing domain for this data // Get the routing domain for this data
let routing_domain = match self let routing_domain = match self
.routing_table() .routing_table()
.routing_domain_for_address(connection_descriptor.remote().address()) .routing_domain_for_address(connection_descriptor.remote_address().address())
{ {
Some(rd) => rd, Some(rd) => rd,
None => { None => {
@ -1778,7 +1783,7 @@ impl NetworkManager {
// Get current external ip/port from registered global dialinfo // Get current external ip/port from registered global dialinfo
let current_addresses: BTreeSet<SocketAddress> = routing_table let current_addresses: BTreeSet<SocketAddress> = routing_table
.all_filtered_dial_info_details( .all_filtered_dial_info_details(
Some(RoutingDomain::PublicInternet), RoutingDomain::PublicInternet.into(),
&dial_info_filter, &dial_info_filter,
) )
.iter() .iter()
@ -1896,12 +1901,8 @@ impl NetworkManager {
.unlocked_inner .unlocked_inner
.node_info_update_single_future .node_info_update_single_future
.single_spawn(async move { .single_spawn(async move {
// Only update if we actually have a valid network class // Only update if we actually have valid signed node info for this routing domain
if matches!( if !this.routing_table().has_valid_own_node_info(routing_domain) {
this.get_network_class(routing_domain)
.unwrap_or(NetworkClass::Invalid),
NetworkClass::Invalid
) {
trace!( trace!(
"not sending node info update because our network class is not yet valid" "not sending node info update because our network class is not yet valid"
); );
@ -1922,7 +1923,7 @@ impl NetworkManager {
unord.push(async move { unord.push(async move {
// Update the node // Update the node
if let Err(e) = rpc if let Err(e) = rpc
.rpc_call_node_info_update(nr.clone, routing_domain) .rpc_call_node_info_update(nr.clone(), routing_domain)
.await .await
{ {
// Not fatal, but we should be able to see if this is happening // Not fatal, but we should be able to see if this is happening

View File

@ -614,7 +614,7 @@ impl Network {
return; return;
} }
// Add network to local networks table // Add network to local networks table
for addr in intf.addrs { for addr in &intf.addrs {
let netmask = addr.if_addr().netmask(); let netmask = addr.if_addr().netmask();
let network_ip = ipaddr_apply_netmask(addr.if_addr().ip(), netmask); let network_ip = ipaddr_apply_netmask(addr.if_addr().ip(), netmask);
local_networks.insert((network_ip, netmask)); local_networks.insert((network_ip, netmask));

View File

@ -132,8 +132,10 @@ impl DiscoveryContext {
false false
} }
}; };
let filter = let filter = RoutingTable::combine_entry_filters(
RoutingTable::combine_filters(inbound_dial_info_entry_filter, disallow_relays_filter); inbound_dial_info_entry_filter,
disallow_relays_filter,
);
// Find public nodes matching this filter // Find public nodes matching this filter
let peers = self let peers = self
@ -155,7 +157,11 @@ impl DiscoveryContext {
continue; continue;
} }
} }
peer.set_filter(Some(dial_info_filter.clone())); peer.set_filter(Some(
NodeRefFilter::new()
.with_routing_domain(RoutingDomain::PublicInternet)
.with_dial_info_filter(dial_info_filter.clone()),
));
if let Some(sa) = self.request_public_address(peer.clone()).await { if let Some(sa) = self.request_public_address(peer.clone()).await {
return Some((sa, peer)); return Some((sa, peer));
} }
@ -764,7 +770,7 @@ impl Network {
// Get existing public dial info // Get existing public dial info
let existing_public_dial_info: HashSet<DialInfoDetail> = routing_table let existing_public_dial_info: HashSet<DialInfoDetail> = routing_table
.all_filtered_dial_info_details( .all_filtered_dial_info_details(
Some(RoutingDomain::PublicInternet), RoutingDomain::PublicInternet.into(),
&DialInfoFilter::all(), &DialInfoFilter::all(),
) )
.into_iter() .into_iter()

View File

@ -287,14 +287,11 @@ impl Network {
// Register local dial info // Register local dial info
for di in &local_dial_info_list { for di in &local_dial_info_list {
// If the local interface address is global, then register global dial info
xxx write routing table sieve for routing domain from dialinfo and local network detection and registration // if no other public address is specified
// If the local interface address is global, or we are enabling local peer scope
// register global dial info if no public address is specified
if !detect_address_changes if !detect_address_changes
&& public_address.is_none() && public_address.is_none()
&& (di.is_global() || enable_local_peer_scope) && routing_table.ensure_dial_info_is_valid(RoutingDomain::PublicInternet, &di)
{ {
routing_table.register_dial_info( routing_table.register_dial_info(
RoutingDomain::PublicInternet, RoutingDomain::PublicInternet,
@ -455,7 +452,7 @@ xxx write routing table sieve for routing domain from dialinfo and local network
if !detect_address_changes if !detect_address_changes
&& url.is_none() && url.is_none()
&& (socket_address.address().is_global() || enable_local_peer_scope) && routing_table.ensure_dial_info_is_valid(RoutingDomain::PublicInternet, &local_di)
{ {
// Register public dial info // Register public dial info
routing_table.register_dial_info( routing_table.register_dial_info(
@ -625,7 +622,7 @@ xxx write routing table sieve for routing domain from dialinfo and local network
// Register global dial info if no public address is specified // Register global dial info if no public address is specified
if !detect_address_changes if !detect_address_changes
&& public_address.is_none() && public_address.is_none()
&& (di.is_global() || enable_local_peer_scope) && routing_table.ensure_dial_info_is_valid(RoutingDomain::PublicInternet, &di)
{ {
routing_table.register_dial_info( routing_table.register_dial_info(
RoutingDomain::PublicInternet, RoutingDomain::PublicInternet,

View File

@ -197,11 +197,7 @@ 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 { async move { routing_table.reverse_find_node(nr, true).await },
routing_table
.reverse_find_node(RoutingDomain::PublicInternet, nr, true)
.await
},
); );
} }
} }
@ -303,12 +299,10 @@ 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 let _ = routing_table.find_target(nr.clone()).await;
.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.signed_node_info_has_valid_signature(RoutingDomain::PublicInternet) {
log_net!(warn log_net!(warn
"bootstrap at {:?} did not return valid signed node info", "bootstrap at {:?} did not return valid signed node info",
nr nr
@ -316,9 +310,7 @@ 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 routing_table.reverse_find_node(nr, true).await
.reverse_find_node(RoutingDomain::PublicInternet, nr, true)
.await
} }
}); });
} }
@ -335,7 +327,9 @@ impl NetworkManager {
fn ping_validator_public_internet( fn ping_validator_public_internet(
&self, &self,
cur_ts: u64, cur_ts: u64,
unord: &mut FuturesUnordered, unord: &mut FuturesUnordered<
SendPinBoxFuture<Result<NetworkResult<Answer<SenderInfo>>, RPCError>>,
>,
) -> EyreResult<()> { ) -> EyreResult<()> {
let rpc = self.rpc_processor(); let rpc = self.rpc_processor();
let routing_table = self.routing_table(); let routing_table = self.routing_table();
@ -352,7 +346,7 @@ impl NetworkManager {
// Get our publicinternet dial info // Get our publicinternet dial info
let dids = routing_table.all_filtered_dial_info_details( let dids = routing_table.all_filtered_dial_info_details(
RoutingDomainSet::only(RoutingDomain::PublicInternet), RoutingDomain::PublicInternet.into(),
&DialInfoFilter::all(), &DialInfoFilter::all(),
); );
@ -381,14 +375,10 @@ impl NetworkManager {
if needs_ping { if needs_ping {
let rpc = rpc.clone(); let rpc = rpc.clone();
let dif = did.dial_info.make_filter(); let dif = did.dial_info.make_filter();
let nr_filtered = nr.filtered_clone(dif); let nr_filtered =
nr.filtered_clone(NodeRefFilter::new().with_dial_info_filter(dif));
log_net!("--> Keepalive ping to {:?}", nr_filtered); log_net!("--> Keepalive ping to {:?}", nr_filtered);
unord.push( unord.push(async move { rpc.rpc_call_status(nr_filtered).await }.boxed());
async move {
rpc.rpc_call_status(Some(routing_domain), nr_filtered).await
}
.boxed(),
);
did_pings = true; did_pings = true;
} }
} }
@ -398,9 +388,7 @@ impl NetworkManager {
// any mapped ports to preserve // any mapped ports to preserve
if !did_pings { if !did_pings {
let rpc = rpc.clone(); let rpc = rpc.clone();
unord.push( unord.push(async move { rpc.rpc_call_status(nr).await }.boxed());
async move { rpc.rpc_call_status(Some(routing_domain), nr).await }.boxed(),
);
} }
} }
@ -413,7 +401,9 @@ impl NetworkManager {
fn ping_validator_local_network( fn ping_validator_local_network(
&self, &self,
cur_ts: u64, cur_ts: u64,
unord: &mut FuturesUnordered, unord: &mut FuturesUnordered<
SendPinBoxFuture<Result<NetworkResult<Answer<SenderInfo>>, RPCError>>,
>,
) -> EyreResult<()> { ) -> EyreResult<()> {
let rpc = self.rpc_processor(); let rpc = self.rpc_processor();
let routing_table = self.routing_table(); let routing_table = self.routing_table();
@ -423,7 +413,7 @@ impl NetworkManager {
// Get our LocalNetwork dial info // Get our LocalNetwork dial info
let dids = routing_table.all_filtered_dial_info_details( let dids = routing_table.all_filtered_dial_info_details(
RoutingDomainSet::only(RoutingDomain::LocalNetwork), RoutingDomain::LocalNetwork.into(),
&DialInfoFilter::all(), &DialInfoFilter::all(),
); );
@ -432,7 +422,7 @@ impl NetworkManager {
let rpc = rpc.clone(); let rpc = rpc.clone();
// Just do a single ping with the best protocol for all the nodes // 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()); unord.push(async move { rpc.rpc_call_status(nr).await }.boxed());
} }
Ok(()) Ok(())
@ -476,7 +466,7 @@ impl NetworkManager {
stop_token: StopToken, stop_token: StopToken,
) -> EyreResult<()> { ) -> EyreResult<()> {
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let mut unord = FuturesOrdered::new(); let mut ord = FuturesOrdered::new();
let min_peer_count = { let min_peer_count = {
let c = self.config.get(); let c = self.config.get();
c.network.dht.min_peer_count as usize c.network.dht.min_peer_count as usize
@ -486,18 +476,18 @@ impl NetworkManager {
// even the unreliable ones, and ask them to find nodes close to our node too // even the unreliable ones, and ask them to find nodes close to our node too
let noderefs = routing_table.find_fastest_nodes( let noderefs = routing_table.find_fastest_nodes(
min_peer_count, min_peer_count,
None, |_k, _v| true,
|k: DHTKey, v: Option<Arc<BucketEntry>>| { |k: DHTKey, v: Option<Arc<BucketEntry>>| {
NodeRef::new(self.clone(), k, v.unwrap().clone(), None) NodeRef::new(routing_table.clone(), k, v.unwrap().clone(), None)
}, },
); );
for nr in noderefs { for nr in noderefs {
let routing_table = routing_table.clone(); let routing_table = routing_table.clone();
unord.push(async move { routing_table.reverse_find_node(nr, false).await }); ord.push_back(async move { routing_table.reverse_find_node(nr, false).await });
} }
// do peer minimum search in order from fastest to slowest // 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(_)) = ord.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(RoutingDomain, ProtocolType, AddressType); struct LastConnectionKey(ProtocolType, AddressType);
/// Bucket entry information specific to the LocalNetwork RoutingDomain /// Bucket entry information specific to the LocalNetwork RoutingDomain
#[derive(Debug)] #[derive(Debug)]
@ -148,17 +148,11 @@ impl BucketEntryInner {
// 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,
) { ) {
// Don't allow invalid signatures unless we are explicitly allowing it
if !allow_invalid_signature && !signed_node_info.signature.valid {
log_rtab!(debug "Invalid signature on signed node info: {:?}", signed_node_info);
return;
}
// 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 signed_node_info.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,
}; };
@ -208,31 +202,23 @@ impl BucketEntryInner {
false false
} }
pub fn has_valid_signed_node_info(&self, routing_domain_set: RoutingDomainSet) -> bool { pub fn node_info(&self, routing_domain: RoutingDomain) -> Option<&NodeInfo> {
for routing_domain in routing_domain_set {
// 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,
};
if let Some(sni) = opt_current_sni {
if sni.is_valid() {
return true;
}
}
}
false
}
pub fn node_info(&self, routing_domain: RoutingDomain) -> Option<NodeInfo> {
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.as_ref().map(|s| s.node_info.clone()) opt_current_sni.as_ref().map(|s| &s.node_info)
} }
pub fn peer_info(&self, key: DHTKey, routing_domain: RoutingDomain) -> Option<PeerInfo> { pub fn signed_node_info(&self, routing_domain: RoutingDomain) -> Option<&SignedNodeInfo> {
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.as_ref().map(|s| s.as_ref())
}
pub fn make_peer_info(&self, key: DHTKey, routing_domain: RoutingDomain) -> Option<PeerInfo> {
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,
@ -253,18 +239,14 @@ impl BucketEntryInner {
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 {
if sni.is_valid() { return Some(routing_domain);
return Some(routing_domain);
}
} }
} }
None None
} }
fn descriptor_to_key(&self, last_connection: ConnectionDescriptor) -> LastConnectionKey { 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(),
) )
@ -285,17 +267,23 @@ impl BucketEntryInner {
// Gets the best 'last connection' that matches a set of routing domain, 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, routing_table_inner: &RoutingTableInner,
dial_info_filter: Option<DialInfoFilter>, node_ref_filter: &Option<NodeRefFilter>,
) -> 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 nrf = node_ref_filter.unwrap_or_default();
for rd in routing_domain_set { for pt in nrf.dial_info_filter.protocol_type_set {
for pt in dif.protocol_type_set { for at in nrf.dial_info_filter.address_type_set {
for at in dif.address_type_set { let key = LastConnectionKey(pt, at);
let key = LastConnectionKey(rd, pt, at); if let Some(v) = self.last_connections.get(&key) {
if let Some(v) = self.last_connections.get(&key) { // Verify this connection could be in the filtered routing domain
return Some(*v); let address = v.0.remote_address().address();
if let Some(rd) =
RoutingTable::routing_domain_for_address_inner(routing_table_inner, address)
{
if nrf.routing_domain_set.contains(rd) {
return Some(*v);
}
} }
} }
} }

View File

@ -52,7 +52,10 @@ impl RoutingTable {
} }
// Make a filter that wraps another filter // Make a filter that wraps another filter
pub fn combine_filters<F, G>(mut f1: F, mut f2: G) -> impl FnMut(&BucketEntryInner) -> bool pub fn combine_entry_filters<F, G>(
mut f1: F,
mut f2: G,
) -> impl FnMut(&BucketEntryInner) -> bool
where where
F: FnMut(&BucketEntryInner) -> bool, F: FnMut(&BucketEntryInner) -> bool,
G: FnMut(&BucketEntryInner) -> bool, G: FnMut(&BucketEntryInner) -> bool,
@ -81,7 +84,7 @@ impl RoutingTable {
// count // count
node_count, node_count,
// filter // filter
Some(|_k: DHTKey, v: Option<Arc<BucketEntry>>| { |_k: DHTKey, v: Option<Arc<BucketEntry>>| {
let entry = v.unwrap(); let entry = v.unwrap();
entry.with(|e| { entry.with(|e| {
// skip nodes on local network // skip nodes on local network
@ -95,7 +98,7 @@ impl RoutingTable {
// skip nodes that dont match entry filter // skip nodes that dont match entry filter
entry_filter(e) entry_filter(e)
}) })
}), },
// transform // transform
|k: DHTKey, v: Option<Arc<BucketEntry>>| { |k: DHTKey, v: Option<Arc<BucketEntry>>| {
NodeRef::new(self.clone(), k, v.unwrap().clone(), None) NodeRef::new(self.clone(), k, v.unwrap().clone(), None)
@ -118,16 +121,16 @@ impl RoutingTable {
// count // count
protocol_types.len() * 2 * max_per_type, protocol_types.len() * 2 * max_per_type,
// filter // filter
Some(move |_k: DHTKey, v: Option<Arc<BucketEntry>>| { move |_k: DHTKey, v: Option<Arc<BucketEntry>>| {
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(RoutingDomainSet::only(RoutingDomain::LocalNetwork)) { if e.has_node_info(RoutingDomain::LocalNetwork.into()) {
return false; return false;
} }
// does it have some dial info we need? // does it have some dial info we need?
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 matches!(did.dial_info.address_type(), AddressType::IPV4) { if matches!(did.dial_info.address_type(), AddressType::IPV4) {
@ -157,7 +160,7 @@ impl RoutingTable {
.map(filter) .map(filter)
.unwrap_or(false) .unwrap_or(false)
}) })
}), },
// transform // transform
|k: DHTKey, v: Option<Arc<BucketEntry>>| { |k: DHTKey, v: Option<Arc<BucketEntry>>| {
NodeRef::new(self.clone(), k, v.unwrap().clone(), None) NodeRef::new(self.clone(), k, v.unwrap().clone(), None)
@ -167,14 +170,16 @@ impl RoutingTable {
pub fn filter_has_valid_signed_node_info( pub fn filter_has_valid_signed_node_info(
&self, &self,
routing_domain: RoutingDomain,
v: Option<Arc<BucketEntry>>, v: Option<Arc<BucketEntry>>,
own_peer_info_is_valid: bool,
routing_domain_set: RoutingDomainSet,
) -> bool { ) -> bool {
let routing_table = self.clone();
match v { match v {
None => own_peer_info_is_valid, None => self.has_valid_own_node_info(routing_domain),
Some(entry) => entry.with(|e| e.has_valid_signed_node_info(routing_domain_set)), Some(entry) => entry.with(|e| {
e.signed_node_info(routing_domain.into())
.map(|sni| sni.has_valid_signature())
.unwrap_or(false)
}),
} }
} }
@ -183,12 +188,10 @@ impl RoutingTable {
routing_domain: RoutingDomain, routing_domain: RoutingDomain,
k: DHTKey, k: DHTKey,
v: Option<Arc<BucketEntry>>, v: Option<Arc<BucketEntry>>,
own_peer_info: &PeerInfo,
) -> PeerInfo { ) -> PeerInfo {
let routing_table = self.clone();
match v { match v {
None => own_peer_info.clone(), None => self.get_own_peer_info(routing_domain),
Some(entry) => entry.with(|e| e.peer_info(k, routing_domain).unwrap()), Some(entry) => entry.with(|e| e.make_peer_info(k, routing_domain).unwrap()),
} }
} }
@ -246,8 +249,8 @@ impl RoutingTable {
pub fn find_fastest_nodes<T, F, O>( pub fn find_fastest_nodes<T, F, O>(
&self, &self,
node_count: usize, node_count: usize,
mut filter: Option<F>, mut filter: F,
transform: T, mut transform: T,
) -> Vec<O> ) -> Vec<O>
where where
F: FnMut(DHTKey, Option<Arc<BucketEntry>>) -> bool, F: FnMut(DHTKey, Option<Arc<BucketEntry>>) -> bool,
@ -264,7 +267,7 @@ impl RoutingTable {
if entry.with(|e| e.state(cur_ts) == BucketEntryState::Dead) { if entry.with(|e| e.state(cur_ts) == BucketEntryState::Dead) {
false false
} else { } else {
filter.as_mut().map(|f| f(k, v)).unwrap_or(true) filter(k, v)
} }
} else { } else {
// always filter out self peer, as it is irrelevant to the 'fastest nodes' search // always filter out self peer, as it is irrelevant to the 'fastest nodes' search
@ -328,12 +331,12 @@ impl RoutingTable {
pub fn find_closest_nodes<F, T, O>( pub fn find_closest_nodes<F, T, O>(
&self, &self,
node_id: DHTKey, node_id: DHTKey,
mut filter: Option<F>, mut filter: F,
mut transform: T, mut transform: T,
) -> Vec<O> ) -> Vec<O>
where where
T: FnMut(DHTKey, Option<Arc<BucketEntry>>) -> O,
F: FnMut(DHTKey, Option<Arc<BucketEntry>>) -> bool, F: FnMut(DHTKey, Option<Arc<BucketEntry>>) -> bool,
T: FnMut(DHTKey, Option<Arc<BucketEntry>>) -> O,
{ {
let cur_ts = intf::get_timestamp(); let cur_ts = intf::get_timestamp();
let node_count = { let node_count = {
@ -344,7 +347,7 @@ impl RoutingTable {
node_count, node_count,
cur_ts, cur_ts,
// filter // filter
|k, v| filter.as_mut().map(|f| f(k, v)).unwrap_or(true), filter,
// sort // sort
|(a_key, a_entry), (b_key, b_entry)| { |(a_key, a_entry), (b_key, b_entry)| {
// same nodes are always the same // same nodes are always the same
@ -390,7 +393,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(
RoutingDomainSet::only(RoutingDomain::PublicInternet), RoutingDomain::PublicInternet.into(),
&DialInfoFilter::all(), &DialInfoFilter::all(),
); );
for did in our_dids { for did in our_dids {
@ -417,12 +420,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_node_ref_filter(RoutingDomain::PublicInternet); .get_outbound_dial_info_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(RoutingDomainSet::only(RoutingDomain::LocalNetwork)) { if e.has_node_info(RoutingDomain::LocalNetwork.into()) {
return false; return false;
} }
@ -549,7 +552,7 @@ impl RoutingTable {
let res = network_result_try!( let res = network_result_try!(
rpc_processor rpc_processor
.clone() .clone()
.rpc_call_find_node(Destination::direct(node_ref), node_id,) .rpc_call_find_node(Destination::direct(node_ref), node_id)
.await? .await?
); );
@ -560,37 +563,24 @@ impl RoutingTable {
} }
#[instrument(level = "trace", skip(self), ret, err)] #[instrument(level = "trace", skip(self), ret, err)]
pub async fn find_self( pub async fn find_self(&self, node_ref: NodeRef) -> EyreResult<NetworkResult<Vec<NodeRef>>> {
&self,
routing_domain: RoutingDomain,
node_ref: NodeRef,
) -> EyreResult<NetworkResult<Vec<NodeRef>>> {
let node_id = self.node_id(); let node_id = self.node_id();
self.find_node(routing_domain, node_ref, node_id).await self.find_node(node_ref, node_id).await
} }
#[instrument(level = "trace", skip(self), ret, err)] #[instrument(level = "trace", skip(self), ret, err)]
pub async fn find_target( pub async fn find_target(&self, node_ref: NodeRef) -> EyreResult<NetworkResult<Vec<NodeRef>>> {
&self,
routing_domain: RoutingDomain,
node_ref: NodeRef,
) -> EyreResult<NetworkResult<Vec<NodeRef>>> {
let node_id = node_ref.node_id(); let node_id = node_ref.node_id();
self.find_node(routing_domain, node_ref, node_id).await self.find_node(node_ref, node_id).await
} }
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
pub async fn reverse_find_node( pub async fn reverse_find_node(&self, node_ref: NodeRef, wide: bool) {
&self,
routing_domain: RoutingDomain,
node_ref: NodeRef,
wide: bool,
) {
// Ask bootstrap node to 'find' our own node so we can get some more nodes near ourselves // Ask bootstrap node to 'find' our own node so we can get some more nodes near ourselves
// and then contact those nodes to inform -them- that we exist // and then contact those nodes to inform -them- that we exist
// Ask bootstrap server for nodes closest to our own node // Ask bootstrap server for nodes closest to our own node
let closest_nodes = network_result_value_or_log!(debug match self.find_self(routing_domain, node_ref.clone()).await { let closest_nodes = network_result_value_or_log!(debug match self.find_self(node_ref.clone()).await {
Err(e) => { Err(e) => {
log_rtab!(error log_rtab!(error
"find_self failed for {:?}: {:?}", "find_self failed for {:?}: {:?}",
@ -606,7 +596,7 @@ impl RoutingTable {
// Ask each node near us to find us as well // Ask each node near us to find us as well
if wide { if wide {
for closest_nr in closest_nodes { for closest_nr in closest_nodes {
network_result_value_or_log!(debug match self.find_self(routing_domain, closest_nr.clone()).await { network_result_value_or_log!(debug match self.find_self(closest_nr.clone()).await {
Err(e) => { Err(e) => {
log_rtab!(error log_rtab!(error
"find_self failed for {:?}: {:?}", "find_self failed for {:?}: {:?}",

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_domain_editor;
mod routing_domains; mod routing_domains;
mod stats_accounting; mod stats_accounting;
mod tasks; mod tasks;
@ -18,6 +19,7 @@ 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_domain_editor::*;
pub use routing_domains::*; pub use routing_domains::*;
pub use stats_accounting::*; pub use stats_accounting::*;
@ -138,11 +140,13 @@ 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> { pub fn routing_domain_for_address_inner(
let inner = self.inner.read(); inner: &RoutingTableInner,
address: Address,
) -> Option<RoutingDomain> {
for rd in RoutingDomain::all() { for rd in RoutingDomain::all() {
let can_contain = let can_contain =
Self::with_routing_domain(&*inner, rd, |rdd| rdd.can_contain_address(address)); Self::with_routing_domain(inner, rd, |rdd| rdd.can_contain_address(address));
if can_contain { if can_contain {
return Some(rd); return Some(rd);
} }
@ -150,6 +154,11 @@ impl RoutingTable {
None None
} }
pub fn routing_domain_for_address(&self, address: Address) -> Option<RoutingDomain> {
let inner = self.inner.read();
Self::routing_domain_for_address_inner(&*inner, address)
}
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(&dyn RoutingDomainDetail) -> R, F: FnOnce(&dyn RoutingDomainDetail) -> R,
@ -256,6 +265,36 @@ impl RoutingTable {
true true
} }
pub fn node_info_is_valid_in_routing_domain(
&self,
routing_domain: RoutingDomain,
node_info: &NodeInfo,
) -> bool {
// Should not be passing around nodeinfo with an invalid network class
if matches!(node_info.network_class, NetworkClass::Invalid) {
return false;
}
// Ensure all of the dial info works in this routing domain
for did in node_info.dial_info_detail_list {
if !self.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) = node_info.relay_peer_info {
let relay_ni = &relay_peer_info.signed_node_info.node_info;
if !self.node_info_is_valid_in_routing_domain(routing_domain, relay_ni) {
return false;
}
}
true
}
#[instrument(level = "debug", skip(self))]
pub fn edit_routing_domain(&self, domain: RoutingDomain) -> RoutingDomainEditor {
RoutingDomainEditor::new(self.clone(), domain)
}
#[instrument(level = "debug", skip(self), err)] #[instrument(level = "debug", skip(self), err)]
pub fn register_dial_info( pub fn register_dial_info(
&self, &self,
@ -349,7 +388,8 @@ impl RoutingTable {
min_version: MIN_VERSION, min_version: MIN_VERSION,
max_version: MAX_VERSION, max_version: MAX_VERSION,
dial_info_detail_list: self.dial_info_details(routing_domain), 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)), relay_peer_info: relay_node
.and_then(|rn| rn.make_peer_info(routing_domain).map(Box::new)),
} }
} }
@ -424,6 +464,8 @@ impl RoutingTable {
Self::with_entries(&*inner, cur_ts, BucketEntryState::Dead, |_rti, e| { Self::with_entries(&*inner, cur_ts, BucketEntryState::Dead, |_rti, e| {
e.with_mut(|e| { e.with_mut(|e| {
e.clear_signed_node_info(RoutingDomain::LocalNetwork); e.clear_signed_node_info(RoutingDomain::LocalNetwork);
e.set_seen_our_node_info(RoutingDomain::LocalNetwork, false);
e.set_updated_since_last_network_change(false);
}); });
Option::<()>::None Option::<()>::None
}); });
@ -549,7 +591,12 @@ 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(self.clone(), k, v, None)); node_refs.push(NodeRef::new(
self.clone(),
k,
v,
Some(NodeRefFilter::new().with_routing_domain(routing_domain)),
));
} }
Option::<()>::None Option::<()>::None
}); });
@ -572,10 +619,15 @@ impl RoutingTable {
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| { if v.with(|e| {
e.has_node_info(RoutingDomainSet::only(routing_domain)) e.has_node_info(routing_domain.into())
&& e.needs_ping(&k, cur_ts, opt_relay_id == Some(k)) && 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,
Some(NodeRefFilter::new().with_routing_domain(routing_domain)),
));
} }
Option::<()>::None Option::<()>::None
}); });
@ -670,12 +722,14 @@ impl RoutingTable {
} }
// Shortcut function to add a node to our routing table if it doesn't exist // Shortcut function to add a node to our routing table if it doesn't exist
// and add the dial info we have for it, since that's pretty common // and add the dial info we have for it. Returns a noderef filtered to
// the routing domain in which this node was registered for convenience.
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: bool,
) -> Option<NodeRef> { ) -> Option<NodeRef> {
// validate signed node info is not something malicious // validate signed node info is not something malicious
if node_id == self.node_id() { if node_id == self.node_id() {
@ -688,11 +742,28 @@ impl RoutingTable {
return None; return None;
} }
} }
if !allow_invalid {
// verify signature
if !signed_node_info.has_valid_signature() {
log_rtab!(debug "signed node info for {} has invalid signature", node_id);
return None;
}
// verify signed node info is valid in this routing domain
if !self
.node_info_is_valid_in_routing_domain(routing_domain, &signed_node_info.node_info)
{
log_rtab!(debug "signed node info for {} not valid in the {:?} routing domain", node_id, routing_domain);
return None;
}
}
self.create_node_ref(node_id, |e| { self.create_node_ref(node_id, |e| {
e.update_signed_node_info(signed_node_info, allow_invalid_signature); e.update_signed_node_info(routing_domain, signed_node_info);
}) })
.map(|mut nr| { .map(|mut nr| {
nr.set_filter(Some(NodeRefFilter::new().with_routing_domain(signed_node_info.routing_domain))) nr.set_filter(Some(
NodeRefFilter::new().with_routing_domain(routing_domain),
));
nr nr
}) })
} }

View File

@ -14,7 +14,7 @@ pub struct NodeRefFilter {
impl Default for NodeRefFilter { impl Default for NodeRefFilter {
fn default() -> Self { fn default() -> Self {
self.new() Self::new()
} }
} }
@ -27,7 +27,7 @@ impl NodeRefFilter {
} }
pub fn with_routing_domain(mut self, routing_domain: RoutingDomain) -> Self { pub fn with_routing_domain(mut self, routing_domain: RoutingDomain) -> Self {
self.routing_domain_set = RoutingDomainSet::only(routing_domain); self.routing_domain_set = routing_domain.into();
self self
} }
pub fn with_routing_domain_set(mut self, routing_domain_set: RoutingDomainSet) -> Self { pub fn with_routing_domain_set(mut self, routing_domain_set: RoutingDomainSet) -> Self {
@ -62,7 +62,7 @@ impl NodeRefFilter {
self self
} }
pub fn is_dead(&self) -> bool { pub fn is_dead(&self) -> bool {
self.dial_info_filter.is_empty() || self.routing_domain_set.is_empty() self.dial_info_filter.is_dead() || self.routing_domain_set.is_empty()
} }
} }
@ -154,6 +154,12 @@ impl NodeRef {
.unwrap_or(RoutingDomainSet::all()) .unwrap_or(RoutingDomainSet::all())
} }
pub fn dial_info_filter(&self) -> DialInfoFilter {
self.filter
.map(|f| f.dial_info_filter)
.unwrap_or(DialInfoFilter::all())
}
pub fn best_routing_domain(&self) -> Option<RoutingDomain> { pub fn best_routing_domain(&self) -> Option<RoutingDomain> {
self.operate(|_rti, e| { self.operate(|_rti, e| {
e.best_routing_domain( e.best_routing_domain(
@ -171,9 +177,6 @@ impl NodeRef {
pub fn node_id(&self) -> DHTKey { pub fn node_id(&self) -> DHTKey {
self.node_id 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())
} }
@ -196,8 +199,15 @@ impl NodeRef {
} }
// Per-RoutingDomain accessors // Per-RoutingDomain accessors
pub fn peer_info(&self, routing_domain: RoutingDomain) -> Option<PeerInfo> { pub fn make_peer_info(&self, routing_domain: RoutingDomain) -> Option<PeerInfo> {
self.operate(|_rti, e| e.peer_info(self.node_id(), routing_domain)) self.operate(|_rti, e| e.make_peer_info(self.node_id(), routing_domain))
}
pub fn signed_node_info_has_valid_signature(&self, routing_domain: RoutingDomain) -> bool {
self.operate(|_rti, e| {
e.signed_node_info(routing_domain)
.map(|sni| sni.has_valid_signature())
.unwrap_or(false)
})
} }
pub fn has_seen_our_node_info(&self, routing_domain: RoutingDomain) -> bool { pub fn has_seen_our_node_info(&self, routing_domain: RoutingDomain) -> bool {
self.operate(|_rti, e| e.has_seen_our_node_info(routing_domain)) self.operate(|_rti, e| e.has_seen_our_node_info(routing_domain))
@ -236,6 +246,7 @@ impl NodeRef {
// Register relay node and return noderef // Register relay node and return noderef
self.routing_table.register_node_with_signed_node_info( self.routing_table.register_node_with_signed_node_info(
routing_domain,
t.node_id.key, t.node_id.key,
t.signed_node_info, t.signed_node_info,
false, false,
@ -246,15 +257,12 @@ impl NodeRef {
// Filtered accessors // Filtered accessors
pub fn first_filtered_dial_info_detail(&self) -> Option<DialInfoDetail> { pub fn first_filtered_dial_info_detail(&self) -> Option<DialInfoDetail> {
let routing_domain_set = self.routing_domain_set(); let routing_domain_set = self.routing_domain_set();
let dial_info_filter = self.dial_info_filter();
self.operate(|_rt, e| { self.operate(|_rt, e| {
for routing_domain in routing_domain_set { for routing_domain in routing_domain_set {
if let Some(ni) = e.node_info(routing_domain) { if let Some(ni) = e.node_info(routing_domain) {
let filter = |did: &DialInfoDetail| { let filter = |did: &DialInfoDetail| did.matches_filter(&dial_info_filter);
self.filter
.as_ref()
.map(|f| did.matches_filter(f))
.unwrap_or(true)
};
if let Some(did) = ni.first_filtered_dial_info_detail(filter) { if let Some(did) = ni.first_filtered_dial_info_detail(filter) {
return Some(did); return Some(did);
} }
@ -266,16 +274,13 @@ impl NodeRef {
pub fn all_filtered_dial_info_details<F>(&self) -> Vec<DialInfoDetail> { pub fn all_filtered_dial_info_details<F>(&self) -> Vec<DialInfoDetail> {
let routing_domain_set = self.routing_domain_set(); let routing_domain_set = self.routing_domain_set();
let dial_info_filter = self.dial_info_filter();
let mut out = Vec::new(); let mut out = Vec::new();
self.operate(|_rt, e| { self.operate(|_rt, e| {
for routing_domain in routing_domain_set { for routing_domain in routing_domain_set {
if let Some(ni) = e.node_info(routing_domain) { if let Some(ni) = e.node_info(routing_domain) {
let filter = |did: &DialInfoDetail| { let filter = |did: &DialInfoDetail| did.matches_filter(&dial_info_filter);
self.filter
.as_ref()
.map(|f| did.matches_filter(f))
.unwrap_or(true)
};
if let Some(did) = ni.first_filtered_dial_info_detail(filter) { if let Some(did) = ni.first_filtered_dial_info_detail(filter) {
out.push(did); out.push(did);
} }
@ -288,12 +293,8 @@ 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) = self.operate(|_rti, e| { let (last_connection, last_seen) =
e.last_connection( self.operate(|rti, e| e.last_connection(rti, &self.filter))?;
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,21 @@
use super::*;
enum RoutingDomainChange {}
pub struct RoutingDomainEditor {
routing_table: RoutingTable,
routing_domain: RoutingDomain,
changes: Vec<RoutingDomainChange>,
}
impl RoutingDomainEditor {
pub(super) fn new(routing_table: RoutingTable, routing_domain: RoutingDomain) -> Self {
Self {
routing_table,
routing_domain,
changes: Vec::new(),
}
}
pub fn commit(self) {}
}

View File

@ -27,8 +27,11 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
self.relay_node.clone() self.relay_node.clone()
} }
fn set_relay_node(&mut self, opt_relay_node: Option<NodeRef>) { fn set_relay_node(&mut self, opt_relay_node: Option<NodeRef>) {
self.relay_node = opt_relay_node self.relay_node = opt_relay_node.map(|nr| {
.map(|nr| nr.filtered_clone(NodeRefFilter::new().with_routing_domain(PublicInternet))) nr.filtered_clone(
NodeRefFilter::new().with_routing_domain(RoutingDomain::PublicInternet),
)
})
} }
fn dial_info_details(&self) -> &Vec<DialInfoDetail> { fn dial_info_details(&self) -> &Vec<DialInfoDetail> {
&self.dial_info_details &self.dial_info_details
@ -78,8 +81,9 @@ impl RoutingDomainDetail for LocalInternetRoutingDomainDetail {
self.relay_node.clone() self.relay_node.clone()
} }
fn set_relay_node(&mut self, opt_relay_node: Option<NodeRef>) { fn set_relay_node(&mut self, opt_relay_node: Option<NodeRef>) {
self.relay_node = opt_relay_node self.relay_node = opt_relay_node.map(|nr| {
.map(|nr| nr.filtered_clone(NodeRefFilter::new().with_routing_domain(LocalNetwork))); nr.filtered_clone(NodeRefFilter::new().with_routing_domain(RoutingDomain::LocalNetwork))
});
} }
fn dial_info_details(&self) -> &Vec<DialInfoDetail> { fn dial_info_details(&self) -> &Vec<DialInfoDetail> {
&self.dial_info_details &self.dial_info_details

View File

@ -5,11 +5,11 @@ pub fn encode_public_internet_node_status(
public_internet_node_status: &PublicInternetNodeStatus, public_internet_node_status: &PublicInternetNodeStatus,
builder: &mut veilid_capnp::public_internet_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(public_internet_node_status.will_route);
builder.set_will_tunnel(node_status.will_tunnel); builder.set_will_tunnel(public_internet_node_status.will_tunnel);
builder.set_will_signal(node_status.will_signal); builder.set_will_signal(public_internet_node_status.will_signal);
builder.set_will_relay(node_status.will_relay); builder.set_will_relay(public_internet_node_status.will_relay);
builder.set_will_validate_dial_info(node_status.will_validate_dial_info); builder.set_will_validate_dial_info(public_internet_node_status.will_validate_dial_info);
Ok(()) Ok(())
} }
@ -30,8 +30,8 @@ pub fn encode_local_network_node_status(
local_network_node_status: &LocalNetworkNodeStatus, local_network_node_status: &LocalNetworkNodeStatus,
builder: &mut veilid_capnp::local_network_node_status::Builder, builder: &mut veilid_capnp::local_network_node_status::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
builder.set_will_relay(node_status.will_relay); builder.set_will_relay(local_network_node_status.will_relay);
builder.set_will_validate_dial_info(node_status.will_validate_dial_info); builder.set_will_validate_dial_info(local_network_node_status.will_validate_dial_info);
Ok(()) Ok(())
} }
@ -39,7 +39,7 @@ pub fn encode_local_network_node_status(
pub fn decode_local_network_node_status( pub fn decode_local_network_node_status(
reader: &veilid_capnp::local_network_node_status::Reader, reader: &veilid_capnp::local_network_node_status::Reader,
) -> Result<LocalNetworkNodeStatus, RPCError> { ) -> Result<LocalNetworkNodeStatus, RPCError> {
Ok(NodeStatus { Ok(LocalNetworkNodeStatus {
will_relay: reader.reborrow().get_will_relay(), will_relay: reader.reborrow().get_will_relay(),
will_validate_dial_info: reader.reborrow().get_will_validate_dial_info(), will_validate_dial_info: reader.reborrow().get_will_validate_dial_info(),
}) })
@ -50,17 +50,15 @@ pub fn encode_node_status(
builder: &mut veilid_capnp::node_status::Builder, builder: &mut veilid_capnp::node_status::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
match node_status { match node_status {
NodeStatus::PublicInternetNodeStatus(ns) => { NodeStatus::PublicInternet(ns) => {
let mut pi_builder = builder.reborrow().init_public_internet(); let mut pi_builder = builder.reborrow().init_public_internet();
encode_public_internet_node_status(&ns, &mut pi_builder) encode_public_internet_node_status(&ns, &mut pi_builder)
} }
NodeStatus::LocalNetworkNodeStatus(ns) => { NodeStatus::LocalNetwork(ns) => {
let mut ln_builder = builder.reborrow().init_local_network(); let mut ln_builder = builder.reborrow().init_local_network();
encode_local_network_node_status(&ns, &mut ln_builder) encode_local_network_node_status(&ns, &mut ln_builder)
} }
} }
Ok(())
} }
pub fn decode_node_status( pub fn decode_node_status(
@ -72,7 +70,7 @@ pub fn decode_node_status(
.map_err(RPCError::map_internal("invalid node status"))? .map_err(RPCError::map_internal("invalid node status"))?
{ {
veilid_capnp::node_status::PublicInternet(pi) => { veilid_capnp::node_status::PublicInternet(pi) => {
let r = r.map_err(RPCError::protocol)?; let r = pi.map_err(RPCError::protocol)?;
let pins = decode_public_internet_node_status(&r)?; let pins = decode_public_internet_node_status(&r)?;
NodeStatus::PublicInternet(pins) NodeStatus::PublicInternet(pins)
} }

View File

@ -58,22 +58,25 @@ impl RPCOperationKind {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RPCOperation { pub struct RPCOperation {
op_id: u64, op_id: u64,
sender_info: Option<SignedNodeInfo>, sender_node_info: Option<SignedNodeInfo>,
kind: RPCOperationKind, kind: RPCOperationKind,
} }
impl RPCOperation { impl RPCOperation {
pub fn new_question(question: RPCQuestion, sender_info: Option<SignedNodeInfo>) -> Self { pub fn new_question(question: RPCQuestion, sender_node_info: Option<SignedNodeInfo>) -> Self {
Self { Self {
op_id: intf::get_random_u64(), op_id: intf::get_random_u64(),
sender_info, sender_node_info,
kind: RPCOperationKind::Question(question), kind: RPCOperationKind::Question(question),
} }
} }
pub fn new_statement(statement: RPCStatement, sender_info: Option<SignedNodeInfo>) -> Self { pub fn new_statement(
statement: RPCStatement,
sender_node_info: Option<SignedNodeInfo>,
) -> Self {
Self { Self {
op_id: intf::get_random_u64(), op_id: intf::get_random_u64(),
sender_info, sender_node_info,
kind: RPCOperationKind::Statement(statement), kind: RPCOperationKind::Statement(statement),
} }
} }
@ -81,11 +84,11 @@ impl RPCOperation {
pub fn new_answer( pub fn new_answer(
request: &RPCOperation, request: &RPCOperation,
answer: RPCAnswer, answer: RPCAnswer,
sender_info: Option<SignedNodeInfo>, sender_node_info: Option<SignedNodeInfo>,
) -> Self { ) -> Self {
Self { Self {
op_id: request.op_id, op_id: request.op_id,
sender_info, sender_node_info,
kind: RPCOperationKind::Answer(answer), kind: RPCOperationKind::Answer(answer),
} }
} }
@ -94,8 +97,8 @@ impl RPCOperation {
self.op_id self.op_id
} }
pub fn sender_info(&self) -> Option<&SignedNodeInfo> { pub fn sender_node_info(&self) -> Option<&SignedNodeInfo> {
self.sender_info.as_ref() self.sender_node_info.as_ref()
} }
pub fn kind(&self) -> &RPCOperationKind { pub fn kind(&self) -> &RPCOperationKind {
@ -112,8 +115,10 @@ 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 sender_node_info = if operation_reader.has_sender_node_info() {
let sni_reader = operation_reader.get_sender_info(); let sni_reader = operation_reader
.get_sender_node_info()
.map_err(RPCError::protocol)?;
let sni = decode_signed_node_info(&sni_reader, sender_node_id, true)?; let sni = decode_signed_node_info(&sni_reader, sender_node_id, true)?;
Some(sni) Some(sni)
} else { } else {
@ -125,7 +130,7 @@ impl RPCOperation {
Ok(RPCOperation { Ok(RPCOperation {
op_id, op_id,
sender_info, sender_node_info,
kind, kind,
}) })
} }
@ -134,9 +139,9 @@ impl RPCOperation {
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 { if let Some(sender_info) = self.sender_node_info {
let si_builder = builder.reborrow().init_sender_info(); let si_builder = builder.reborrow().init_sender_node_info();
encode_signed_node_info(&self.sender_info, &mut si_builder)?; encode_signed_node_info(&sender_info, &mut si_builder)?;
} }
Ok(()) Ok(())
} }

View File

@ -48,6 +48,57 @@ impl Destination {
safety_route_spec: None, safety_route_spec: None,
} }
} }
// pub fn target_id(&self) -> DHTKey {
// match self {
// Destination::Direct {
// target,
// safety_route_spec,
// } => target.node_id(),
// Destination::Relay {
// relay,
// target,
// safety_route_spec,
// } => *target,
// Destination::PrivateRoute {
// private_route,
// safety_route_spec,
// } => {}
// }
// }
// pub fn best_routing_domain(&self) -> RoutingDomain {
// match self {
// Destination::Direct {
// target,
// safety_route_spec,
// } => {
// if safety_route_spec.is_some() {
// RoutingDomain::PublicInternet
// } else {
// target
// .best_routing_domain()
// .unwrap_or(RoutingDomain::PublicInternet)
// }
// }
// Destination::Relay {
// relay,
// target,
// safety_route_spec,
// } => {
// if safety_route_spec.is_some() {
// RoutingDomain::PublicInternet
// } else {
// relay
// .best_routing_domain()
// .unwrap_or(RoutingDomain::PublicInternet)
// }
// }
// Destination::PrivateRoute {
// private_route: _,
// safety_route_spec: _,
// } => RoutingDomain::PublicInternet,
// }
// }
pub fn safety_route_spec(&self) -> Option<Arc<SafetyRouteSpec>> { pub fn safety_route_spec(&self) -> Option<Arc<SafetyRouteSpec>> {
match self { match self {
@ -100,7 +151,6 @@ impl fmt::Display for Destination {
match self { match self {
Destination::Direct { Destination::Direct {
target, target,
routing_domain,
safety_route_spec, safety_route_spec,
} => { } => {
let sr = safety_route_spec let sr = safety_route_spec

View File

@ -200,22 +200,8 @@ impl RPCProcessor {
/// Determine if a NodeInfo can be placed into the specified routing domain /// Determine if a NodeInfo can be placed into the specified routing domain
fn filter_node_info(&self, routing_domain: RoutingDomain, node_info: &NodeInfo) -> bool { fn filter_node_info(&self, routing_domain: RoutingDomain, node_info: &NodeInfo) -> bool {
// reject attempts to include non-public addresses in results let routing_table = self.routing_table();
for did in &node_info.dial_info_detail_list { routing_table.node_info_is_valid_in_routing_domain(routing_domain, &node_info)
if !did.dial_info.is_global() {
// non-public address causes rejection
return false;
}
}
if let Some(rpi) = &node_info.relay_peer_info {
for did in &rpi.signed_node_info.node_info.dial_info_detail_list {
if !did.dial_info.is_global() {
// non-public address causes rejection
return false;
}
}
}
true
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -360,9 +346,6 @@ impl RPCProcessor {
waitable_reply.node_ref.stats_question_lost(); waitable_reply.node_ref.stats_question_lost();
} }
Ok(TimeoutOr::Value((rpcreader, _))) => { Ok(TimeoutOr::Value((rpcreader, _))) => {
// Note that the remote node definitely received this node info since we got a reply
waitable_reply.node_ref.set_seen_our_node_info();
// Reply received // Reply received
let recv_ts = intf::get_timestamp(); let recv_ts = intf::get_timestamp();
waitable_reply.node_ref.stats_answer_rcvd( waitable_reply.node_ref.stats_answer_rcvd(
@ -403,13 +386,11 @@ impl RPCProcessor {
match dest { match dest {
Destination::Direct { Destination::Direct {
target: node_ref, target: node_ref,
routing_domain,
safety_route_spec, safety_route_spec,
} }
| Destination::Relay { | Destination::Relay {
relay: node_ref, relay: node_ref,
target: _, target: _,
routing_domain,
safety_route_spec, safety_route_spec,
} => { } => {
// Send to a node without a private route // Send to a node without a private route
@ -419,7 +400,6 @@ impl RPCProcessor {
let (node_ref, node_id) = if let Destination::Relay { let (node_ref, node_id) = if let Destination::Relay {
relay: _, relay: _,
target: dht_key, target: dht_key,
routing_domain: _,
safety_route_spec: _, safety_route_spec: _,
} = dest } = dest
{ {
@ -508,6 +488,53 @@ impl RPCProcessor {
}) })
} }
// Get signed node info to package with RPC messages to improve
// routing table caching when it is okay to do so
// This is only done in the PublicInternet routing domain because
// as far as we can tell this is the only domain that will really benefit
fn get_sender_signed_node_info(&self, dest: &Destination) -> Option<SignedNodeInfo> {
// Don't do this if the sender is to remain private
if dest.safety_route_spec().is_some() {
return None;
}
// Don't do this if our own signed node info isn't valid yet
let routing_table = self.routing_table();
if !routing_table.has_valid_own_node_info(RoutingDomain::PublicInternet) {
return None;
}
match dest {
Destination::Direct {
target,
safety_route_spec: _,
} => {
// If the target has seen our node info already don't do this
if target.has_seen_our_node_info(RoutingDomain::PublicInternet) {
return None;
}
Some(routing_table.get_own_signed_node_info(RoutingDomain::PublicInternet))
}
Destination::Relay {
relay: _,
target,
safety_route_spec: _,
} => {
if let Some(target) = routing_table.lookup_node_ref(*target) {
if target.has_seen_our_node_info(RoutingDomain::PublicInternet) {
return None;
}
Some(routing_table.get_own_signed_node_info(RoutingDomain::PublicInternet))
} else {
None
}
}
Destination::PrivateRoute {
private_route: _,
safety_route_spec: _,
} => None,
}
}
// 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), err)] #[instrument(level = "debug", skip(self, question), err)]
async fn question( async fn question(
@ -515,18 +542,11 @@ impl RPCProcessor {
dest: Destination, dest: Destination,
question: RPCQuestion, question: RPCQuestion,
) -> Result<NetworkResult<WaitableReply>, RPCError> { ) -> Result<NetworkResult<WaitableReply>, RPCError> {
// Get sender info if we should send that // 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) { let opt_sender_info = self.get_sender_signed_node_info(&dest);
// 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, opt_sender_info);
let op_id = operation.op_id(); let op_id = operation.op_id();
// Log rpc send // Log rpc send
@ -538,7 +558,7 @@ impl RPCProcessor {
node_id, node_id,
node_ref, node_ref,
hop_count, hop_count,
} = self.render_operation(dest, &operation, safety_route_spec)?; } = self.render_operation(dest, &operation)?;
// If we need to resolve the first hop, do it // If we need to resolve the first hop, do it
let node_ref = match node_ref { let node_ref = match node_ref {
@ -594,14 +614,17 @@ impl RPCProcessor {
} }
// Issue a statement over the network, possibly using an anonymized route // Issue a statement over the network, possibly using an anonymized route
#[instrument(level = "debug", skip(self, statement, safety_route_spec), err)] #[instrument(level = "debug", skip(self, statement), err)]
async fn statement( async fn statement(
&self, &self,
dest: Destination, dest: Destination,
statement: RPCStatement, statement: RPCStatement,
) -> Result<NetworkResult<()>, RPCError> { ) -> Result<NetworkResult<()>, RPCError> {
// Get sender info if we should send that
let opt_sender_info = self.get_sender_signed_node_info(&dest);
// Wrap statement in operation // Wrap statement in operation
let operation = RPCOperation::new_statement(statement); let operation = RPCOperation::new_statement(statement, opt_sender_info);
// Log rpc send // Log rpc send
debug!(target: "rpc_message", dir = "send", kind = "statement", op_id = operation.op_id(), desc = operation.kind().desc(), ?dest); debug!(target: "rpc_message", dir = "send", kind = "statement", op_id = operation.op_id(), desc = operation.kind().desc(), ?dest);
@ -612,7 +635,7 @@ impl RPCProcessor {
node_id, node_id,
node_ref, node_ref,
hop_count: _, hop_count: _,
} = self.render_operation(dest, &operation, safety_route_spec)?; } = self.render_operation(dest, &operation)?;
// If we need to resolve the first hop, do it // If we need to resolve the first hop, do it
let node_ref = match node_ref { let node_ref = match node_ref {
@ -662,7 +685,7 @@ impl RPCProcessor {
// To where should we respond? // To where should we respond?
match respond_to { match respond_to {
RespondTo::Sender(_) => { RespondTo::Sender => {
// Reply directly to the request's source // Reply directly to the request's source
let sender_id = request.header.envelope.get_sender_id(); let sender_id = request.header.envelope.get_sender_id();
@ -672,29 +695,32 @@ impl RPCProcessor {
// If the sender_id is that of the peer, then this is a direct reply // If the sender_id is that of the peer, then this is a direct reply
// else it is a relayed reply through the peer // else it is a relayed reply through the peer
if peer_noderef.node_id() == sender_id { if peer_noderef.node_id() == sender_id {
Destination::Direct(peer_noderef) Destination::direct(peer_noderef)
} else { } else {
Destination::Relay(peer_noderef, sender_id) Destination::relay(peer_noderef, sender_id)
} }
} }
RespondTo::PrivateRoute(pr) => Destination::PrivateRoute(pr.clone()), RespondTo::PrivateRoute(pr) => Destination::private_route(pr.clone()),
} }
} }
// Issue a reply over the network, possibly using an anonymized route // Issue a reply over the network, possibly using an anonymized route
// The request must want a response, or this routine fails // The request must want a response, or this routine fails
#[instrument(level = "debug", skip(self, request, answer, safety_route_spec), err)] #[instrument(level = "debug", skip(self, request, answer), err)]
async fn answer( async fn answer(
&self, &self,
request: RPCMessage, request: RPCMessage,
answer: RPCAnswer, answer: RPCAnswer,
) -> Result<NetworkResult<()>, RPCError> { ) -> Result<NetworkResult<()>, RPCError> {
// Wrap answer in operation
let operation = RPCOperation::new_answer(&request.operation, answer);
// Extract destination from respond_to // Extract destination from respond_to
let dest = self.get_respond_to_destination(&request); let dest = self.get_respond_to_destination(&request);
// Get sender info if we should send that
let opt_sender_info = self.get_sender_signed_node_info(&dest);
// Wrap answer in operation
let operation = RPCOperation::new_answer(&request.operation, answer, opt_sender_info);
// Log rpc send // Log rpc send
debug!(target: "rpc_message", dir = "send", kind = "answer", op_id = operation.op_id(), desc = operation.kind().desc(), ?dest); debug!(target: "rpc_message", dir = "send", kind = "answer", op_id = operation.op_id(), desc = operation.kind().desc(), ?dest);
@ -704,7 +730,7 @@ impl RPCProcessor {
node_id, node_id,
node_ref, node_ref,
hop_count: _, hop_count: _,
} = self.render_operation(dest, &operation, safety_route_spec)?; } = self.render_operation(dest, &operation)?;
// If we need to resolve the first hop, do it // If we need to resolve the first hop, do it
let node_ref = match node_ref { let node_ref = match node_ref {
@ -747,8 +773,7 @@ impl RPCProcessor {
&self, &self,
encoded_msg: RPCMessageEncoded, encoded_msg: RPCMessageEncoded,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
// Get the routing domain this message came over
// Get the routing domain
let routing_domain = encoded_msg.header.routing_domain; let routing_domain = encoded_msg.header.routing_domain;
// Decode the operation // Decode the operation
@ -764,35 +789,34 @@ impl RPCProcessor {
RPCOperation::decode(&op_reader, &sender_node_id)? RPCOperation::decode(&op_reader, &sender_node_id)?
}; };
// Get the sender noderef, incorporating and 'sender node info' we have from a question // Get the sender noderef, incorporating and 'sender node info'
let mut opt_sender_nr: Option<NodeRef> = None; let mut opt_sender_nr: Option<NodeRef> = None;
match operation.kind() { if let Some(sender_node_info) = operation.sender_node_info() {
RPCOperationKind::Question(q) => { // Sender NodeInfo was specified, update our routing table with it
match q.respond_to() { if !self.filter_node_info(RoutingDomain::PublicInternet, &sender_node_info.node_info) {
RespondTo::Sender(Some(sender_ni)) => { return Err(RPCError::invalid_format(
// Sender NodeInfo was specified, update our routing table with it "sender signednodeinfo has invalid peer scope",
if !self.filter_node_info(&sender_ni.node_info) { ));
return Err(RPCError::invalid_format(
"respond_to_sender_signed_node_info has invalid peer scope",
));
}
opt_sender_nr = self.routing_table().register_node_with_signed_node_info(
routing_domain,
sender_node_id,
sender_ni.clone(),
false,
);
}
_ => {}
}
} }
_ => {} opt_sender_nr = self.routing_table().register_node_with_signed_node_info(
}; routing_domain,
sender_node_id,
sender_node_info.clone(),
false,
);
}
// look up sender node, in case it's different than our peer due to relaying
if opt_sender_nr.is_none() { if opt_sender_nr.is_none() {
// look up sender node, in case it's different than our peer due to relaying
opt_sender_nr = self.routing_table().lookup_node_ref(sender_node_id) opt_sender_nr = self.routing_table().lookup_node_ref(sender_node_id)
} }
// Mark this sender as having seen our node info over this routing domain
// because it managed to reach us over that routing domain
if let Some(sender_nr) = &opt_sender_nr {
sender_nr.set_seen_our_node_info(routing_domain);
}
// Make the RPC message // Make the RPC message
let msg = RPCMessage { let msg = RPCMessage {
header: encoded_msg.header, header: encoded_msg.header,

View File

@ -139,7 +139,7 @@ impl RPCProcessor {
operation, operation,
}; };
let operation = let operation =
RPCOperation::new_statement(RPCStatement::new(RPCStatementDetail::Route(route))); RPCOperation::new_statement(RPCStatement::new(RPCStatementDetail::Route(route)), None);
// Convert message to bytes and return it // Convert message to bytes and return it
let mut route_msg = ::capnp::message::Builder::new_default(); let mut route_msg = ::capnp::message::Builder::new_default();

View File

@ -9,7 +9,9 @@ impl RPCProcessor {
dest: Destination, dest: Destination,
key: DHTKey, key: DHTKey,
) -> Result<NetworkResult<Answer<Vec<PeerInfo>>>, RPCError> { ) -> Result<NetworkResult<Answer<Vec<PeerInfo>>>, RPCError> {
let find_node_q = RPCQuestionDetail::FindNodeQ(RPCOperationFindNodeQ { node_id: key }); let find_node_q_detail =
RPCQuestionDetail::FindNodeQ(RPCOperationFindNodeQ { node_id: key });
let find_node_q = RPCQuestion::new(RespondTo::Sender, find_node_q_detail);
// Send the find_node request // Send the find_node request
let waitable_reply = network_result_try!(self.question(dest, find_node_q).await?); let waitable_reply = network_result_try!(self.question(dest, find_node_q).await?);
@ -31,7 +33,10 @@ 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_node_info(&peer_info.signed_node_info.node_info) { if !self.filter_node_info(
RoutingDomain::PublicInternet,
&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",
)); ));
@ -61,23 +66,12 @@ impl RPCProcessor {
let rt3 = routing_table.clone(); let rt3 = routing_table.clone();
// find N nodes closest to the target node in our routing table // find N nodes closest to the target node in our routing table
let own_peer_info = routing_table.get_own_peer_info(RoutingDomain::PublicInternet);
let own_peer_info_is_valid = own_peer_info.signed_node_info.is_valid();
let closest_nodes = routing_table.find_closest_nodes( let closest_nodes = routing_table.find_closest_nodes(
find_node_q.node_id, find_node_q.node_id,
// filter // filter
Some(move |_k, v| { move |_k, v| rt2.filter_has_valid_signed_node_info(RoutingDomain::PublicInternet, v),
rt2.filter_has_valid_signed_node_info(
v,
own_peer_info_is_valid,
Some(RoutingDomain::PublicInternet),
)
}),
// transform // transform
move |k, v| { move |k, v| rt3.transform_to_peer_info(RoutingDomain::PublicInternet, k, v),
rt3.transform_to_peer_info(RoutingDomain::PublicInternet, k, v, &own_peer_info)
},
); );
// Make status answer // Make status answer
@ -87,11 +81,7 @@ impl RPCProcessor {
// Send status answer // Send status answer
let res = self let res = self
.answer( .answer(msg, RPCAnswer::new(RPCAnswerDetail::FindNodeA(find_node_a)))
msg,
RPCAnswer::new(RPCAnswerDetail::FindNodeA(find_node_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

@ -18,7 +18,9 @@ impl RPCProcessor {
// Send the node_info_update request to the specific routing domain requested // 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.filtered_clone(NodeRefFilter::new().with_routing_domain(routing_domain))
),
statement, statement,
) )
.await? .await?
@ -30,6 +32,7 @@ impl RPCProcessor {
#[instrument(level = "trace", skip(self, msg), fields(msg.operation.op_id), err)] #[instrument(level = "trace", skip(self, msg), fields(msg.operation.op_id), err)]
pub(crate) async fn process_node_info_update(&self, msg: RPCMessage) -> Result<(), RPCError> { pub(crate) async fn process_node_info_update(&self, msg: RPCMessage) -> Result<(), RPCError> {
let sender_node_id = msg.header.envelope.get_sender_id(); let sender_node_id = msg.header.envelope.get_sender_id();
let routing_domain = msg.header.routing_domain;
// Get the statement // Get the statement
let node_info_update = match msg.operation.into_kind() { let node_info_update = match msg.operation.into_kind() {
@ -41,14 +44,13 @@ impl RPCProcessor {
}; };
// Update our routing table with signed node info // Update our routing table with signed node info
if !self.filter_node_info(&node_info_update.signed_node_info.node_info) { if !self.filter_node_info(routing_domain, &node_info_update.signed_node_info.node_info) {
log_rpc!(debug log_rpc!(debug "node info doesn't belong in {:?} routing domain: {}", routing_domain, sender_node_id);
"node_info_update has invalid peer scope from {}", sender_node_id
);
return Ok(()); return Ok(());
} }
self.routing_table().register_node_with_signed_node_info( self.routing_table().register_node_with_signed_node_info(
routing_domain,
sender_node_id, sender_node_id,
node_info_update.signed_node_info, node_info_update.signed_node_info,
false, false,

View File

@ -7,7 +7,6 @@ impl RPCProcessor {
pub async fn rpc_call_return_receipt<D: AsRef<[u8]>>( pub async fn rpc_call_return_receipt<D: AsRef<[u8]>>(
self, self,
dest: Destination, dest: Destination,
safety_route: Option<&SafetyRouteSpec>,
receipt: D, receipt: D,
) -> Result<NetworkResult<()>, RPCError> { ) -> Result<NetworkResult<()>, RPCError> {
let receipt = receipt.as_ref().to_vec(); let receipt = receipt.as_ref().to_vec();
@ -16,7 +15,7 @@ impl RPCProcessor {
let statement = RPCStatement::new(RPCStatementDetail::ReturnReceipt(return_receipt)); let statement = RPCStatement::new(RPCStatementDetail::ReturnReceipt(return_receipt));
// Send the return_receipt request // Send the return_receipt request
network_result_try!(self.statement(dest, statement, safety_route).await?); network_result_try!(self.statement(dest, statement).await?);
Ok(NetworkResult::value(())) Ok(NetworkResult::value(()))
} }

View File

@ -7,15 +7,13 @@ impl RPCProcessor {
pub async fn rpc_call_signal( pub async fn rpc_call_signal(
self, self,
dest: Destination, dest: Destination,
safety_route: Option<&SafetyRouteSpec>,
signal_info: SignalInfo, signal_info: SignalInfo,
) -> Result<NetworkResult<()>, RPCError> { ) -> Result<NetworkResult<()>, RPCError> {
//let signed_node_info = self.routing_table().get_own_signed_node_info();
let signal = RPCOperationSignal { signal_info }; let signal = RPCOperationSignal { signal_info };
let statement = RPCStatement::new(RPCStatementDetail::Signal(signal)); let statement = RPCStatement::new(RPCStatementDetail::Signal(signal));
// Send the signal request // Send the signal request
network_result_try!(self.statement(dest, statement, safety_route).await?); network_result_try!(self.statement(dest, statement).await?);
Ok(NetworkResult::value(())) Ok(NetworkResult::value(()))
} }

View File

@ -118,17 +118,15 @@ impl RPCProcessor {
// Ensure the node status from the question is the kind for the routing domain we received the request in // Ensure the node status from the question is the kind for the routing domain we received the request in
match routing_domain { match routing_domain {
RoutingDomain::PublicInternet => { RoutingDomain::PublicInternet => {
if !matches!(status_a.node_status, NodeStatus::PublicInternet(_)) { if !matches!(status_q.node_status, NodeStatus::PublicInternet(_)) {
return Ok(NetworkResult::invalid_message( log_rpc!(debug "node status doesn't match PublicInternet routing domain");
"node status doesn't match PublicInternet routing domain", return Ok(());
));
} }
} }
RoutingDomain::LocalNetwork => { RoutingDomain::LocalNetwork => {
if !matches!(status_a.node_status, NodeStatus::LocalNetwork(_)) { if !matches!(status_q.node_status, NodeStatus::LocalNetwork(_)) {
return Ok(NetworkResult::invalid_message( log_rpc!(debug "node status doesn't match LocalNetwork routing domain");
"node status doesn't match LocalNetwork routing domain", return Ok(());
));
} }
} }
} }

View File

@ -32,7 +32,7 @@ impl RPCProcessor {
// Send the validate_dial_info request // Send the validate_dial_info request
// This can only be sent directly, as relays can not validate dial info // This can only be sent directly, as relays can not validate dial info
network_result_value_or_log!(debug self.statement(Destination::Direct(peer), statement, None) network_result_value_or_log!(debug self.statement(Destination::direct(peer), statement)
.await? => { .await? => {
return Ok(false); return Ok(false);
} }
@ -81,6 +81,7 @@ impl RPCProcessor {
// an ipv6 address // an ipv6 address
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let sender_id = msg.header.envelope.get_sender_id(); let sender_id = msg.header.envelope.get_sender_id();
let routing_domain = msg.header.routing_domain;
let node_count = { let node_count = {
let c = self.config.get(); let c = self.config.get();
c.network.dht.max_find_node_count as usize c.network.dht.max_find_node_count as usize
@ -88,15 +89,18 @@ impl RPCProcessor {
// Filter on nodes that can validate dial info, and can reach a specific dial info // Filter on nodes that can validate dial info, and can reach a specific dial info
let outbound_dial_info_entry_filter = let outbound_dial_info_entry_filter =
RoutingTable::make_outbound_dial_info_entry_filter(dial_info.clone()); RoutingTable::make_outbound_dial_info_entry_filter(
routing_domain,
dial_info.clone(),
);
let will_validate_dial_info_filter = |e: &BucketEntryInner| { let will_validate_dial_info_filter = |e: &BucketEntryInner| {
if let Some(status) = &e.peer_stats().status { if let Some(status) = &e.node_status(routing_domain) {
status.will_validate_dial_info status.will_validate_dial_info()
} else { } else {
true true
} }
}; };
let filter = RoutingTable::combine_filters( let filter = RoutingTable::combine_entry_filters(
outbound_dial_info_entry_filter, outbound_dial_info_entry_filter,
will_validate_dial_info_filter, will_validate_dial_info_filter,
); );
@ -126,7 +130,7 @@ impl RPCProcessor {
// Send the validate_dial_info request // Send the validate_dial_info request
// This can only be sent directly, as relays can not validate dial info // This can only be sent directly, as relays can not validate dial info
network_result_value_or_log!(debug self.statement(Destination::Direct(peer), statement, None) network_result_value_or_log!(debug self.statement(Destination::direct(peer), statement)
.await? => { .await? => {
return Ok(()); return Ok(());
} }

View File

@ -304,25 +304,41 @@ 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 = get_debug_argument_at( let mut routing_domain = None;
while ai < args.len() {
if let Ok(pt) = get_debug_argument_at(
&args, &args,
1, ai,
"debug_contact", "debug_contact",
"protocol_type", "protocol_type",
get_protocol_type, get_protocol_type,
)?; ) {
nr.merge_filter(DialInfoFilter::all().with_protocol_type(pt)); nr.merge_filter(NodeRefFilter::new().with_protocol_type(pt));
if args.len() >= 3 { } else if let Ok(at) =
let at = get_debug_argument_at( get_debug_argument_at(&args, ai, "debug_contact", "address_type", get_address_type)
&args, {
2, nr.merge_filter(NodeRefFilter::new().with_address_type(at));
"debug_contact", } else if let Ok(rd) = get_debug_argument_at(
"address_type", &args,
get_address_type, ai,
)?; "debug_contact",
nr.merge_filter(DialInfoFilter::all().with_address_type(at)); "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;
}
if let Some(routing_domain) = routing_domain {
nr.merge_filter(NodeRefFilter::new().with_routing_domain(routing_domain))
} }
let cm = network_manager.get_contact_method(nr); let cm = network_manager.get_contact_method(nr);
@ -331,11 +347,14 @@ impl VeilidAPI {
} }
async fn debug_ping(&self, args: String) -> Result<String, VeilidAPIError> { async fn debug_ping(&self, args: String) -> Result<String, VeilidAPIError> {
let netman = self.network_manager()?;
let routing_table = netman.routing_table();
let rpc = netman.rpc_processor();
let args: Vec<String> = args.split_whitespace().map(|s| s.to_owned()).collect(); let args: Vec<String> = args.split_whitespace().map(|s| s.to_owned()).collect();
let node_id = get_debug_argument_at(&args, 0, "debug_ping", "node_id", get_dht_key)?; let node_id = get_debug_argument_at(&args, 0, "debug_ping", "node_id", get_dht_key)?;
let routing_table = self.network_manager()?.routing_table();
let mut nr = match routing_table.lookup_node_ref(node_id) { let mut nr = match routing_table.lookup_node_ref(node_id) {
Some(nr) => nr, Some(nr) => nr,
None => return Ok("Node id not found in routing table".to_owned()), None => return Ok("Node id not found in routing table".to_owned()),
@ -347,11 +366,11 @@ impl VeilidAPI {
if let Ok(pt) = if let Ok(pt) =
get_debug_argument_at(&args, ai, "debug_ping", "protocol_type", get_protocol_type) get_debug_argument_at(&args, ai, "debug_ping", "protocol_type", get_protocol_type)
{ {
nr.merge_filter(DialInfoFilter::all().with_protocol_type(pt)); nr.merge_filter(NodeRefFilter::new().with_protocol_type(pt));
} else if let Ok(at) = } else if let Ok(at) =
get_debug_argument_at(&args, ai, "debug_ping", "address_type", get_address_type) get_debug_argument_at(&args, ai, "debug_ping", "address_type", get_address_type)
{ {
nr.merge_filter(DialInfoFilter::all().with_address_type(at)); nr.merge_filter(NodeRefFilter::new().with_address_type(at));
} else if let Ok(rd) = get_debug_argument_at( } else if let Ok(rd) = get_debug_argument_at(
&args, &args,
ai, ai,
@ -370,11 +389,13 @@ impl VeilidAPI {
ai += 1; ai += 1;
} }
let rpc = self.network_manager()?.rpc_processor(); if let Some(routing_domain) = routing_domain {
nr.merge_filter(NodeRefFilter::new().with_routing_domain(routing_domain))
}
// Dump routing table entry // Dump routing table entry
let out = match rpc let out = match rpc
.rpc_call_status(routing_domain, nr) .rpc_call_status(nr)
.await .await
.map_err(VeilidAPIError::internal)? .map_err(VeilidAPIError::internal)?
{ {

View File

@ -460,31 +460,6 @@ pub struct NodeInfo {
} }
impl NodeInfo { impl NodeInfo {
pub fn is_valid_in_routing_domain(
&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,
@ -805,7 +780,7 @@ impl FromStr for SocketAddress {
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, 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,
@ -1449,8 +1424,8 @@ impl SignedNodeInfo {
} }
} }
pub fn is_valid(&self) -> bool { pub fn has_valid_signature(&self) -> bool {
self.signature.valid && self.node_info.is_valid() self.signature.valid
} }
} }