fix contact method for nodes on the same ipblock

This commit is contained in:
Christien Rioux 2024-04-27 19:06:30 -04:00
parent b3c7c93f97
commit 7c7ea4e3c7
4 changed files with 63 additions and 36 deletions

View File

@ -15,11 +15,6 @@ impl Default for NetworkClass {
}
impl NetworkClass {
// Must an inbound relay be kept available?
// In the case of InboundCapable, it is left up to the class of each DialInfo to determine if an inbound relay is required
pub fn inbound_wants_relay(&self) -> bool {
matches!(self, Self::OutboundOnly | Self::WebApp)
}
// Should an outbound relay be kept available?
pub fn outbound_wants_relay(&self) -> bool {
matches!(self, Self::WebApp)

View File

@ -319,17 +319,27 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
}
fn get_contact_method(
&self,
_rti: &RoutingTableInner,
rti: &RoutingTableInner,
peer_a: &PeerInfo,
peer_b: &PeerInfo,
dial_info_filter: DialInfoFilter,
sequencing: Sequencing,
dif_sort: Option<Arc<DialInfoDetailSort>>,
) -> ContactMethod {
let ip6_prefix_size = rti
.unlocked_inner
.config
.get()
.network
.max_connections_per_ip6_prefix_size as usize;
// Get the nodeinfos for convenience
let node_a = peer_a.signed_node_info().node_info();
let node_b = peer_b.signed_node_info().node_info();
// Check to see if these nodes are on the same network
let same_ipblock = node_a.node_is_on_same_ipblock(node_b, ip6_prefix_size);
// Get the node ids that would be used between these peers
let cck = common_crypto_kinds(&peer_a.node_ids().kinds(), &peer_b.node_ids().kinds());
let Some(best_ck) = cck.first().copied() else {
@ -341,13 +351,20 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
let node_b_id = peer_b.node_ids().get(best_ck).unwrap();
// Get the best match dial info for node B if we have it
if let Some(target_did) = first_filtered_dial_info_detail_between_nodes(
node_a,
node_b,
&dial_info_filter,
sequencing,
dif_sort.clone(),
) {
// Don't try direct inbound at all if the two nodes are on the same ipblock to avoid hairpin NAT issues
// as well avoiding direct traffic between same-network nodes. This would be done in the LocalNetwork RoutingDomain.
if let Some(target_did) = (!same_ipblock)
.then(|| {
first_filtered_dial_info_detail_between_nodes(
node_a,
node_b,
&dial_info_filter,
sequencing,
dif_sort.clone(),
)
})
.flatten()
{
// Do we need to signal before going inbound?
if !target_did.class.requires_signal() {
// Go direct without signaling
@ -449,7 +466,7 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
}
}
}
// If the node B has no direct dial info, it needs to have an inbound relay
// If the node B has no direct dial info or is on the same ipblock, it needs to have an inbound relay
else if let Some(node_b_relay) = peer_b.signed_node_info().relay_info() {
// Note that relay_peer_info could be node_a, in which case a connection already exists
// and we only get here if the connection had dropped, in which case node_b is unreachable until
@ -481,13 +498,19 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
///////// Reverse connection
// Get the best match dial info for an reverse inbound connection from node B to node A
if let Some(reverse_did) = first_filtered_dial_info_detail_between_nodes(
node_b,
node_a,
&dial_info_filter,
sequencing,
dif_sort.clone(),
) {
// unless both nodes are on the same ipblock
if let Some(reverse_did) = (!same_ipblock)
.then(|| {
first_filtered_dial_info_detail_between_nodes(
node_b,
node_a,
&dial_info_filter,
sequencing,
dif_sort.clone(),
)
})
.flatten()
{
// Can we receive a direct reverse connection?
if !reverse_did.class.requires_signal() {
return ContactMethod::SignalReverse(node_b_relay_id, node_b_id);

View File

@ -146,7 +146,11 @@ impl RoutingTable {
// Get all our outbound protocol/address types
let outbound_dif = self.get_outbound_dial_info_filter(RoutingDomain::PublicInternet);
let mapped_port_info = self.get_low_level_port_info();
let own_node_info = self
.get_own_peer_info(RoutingDomain::PublicInternet)
.signed_node_info()
.node_info()
.clone();
let ip6_prefix_size = self
.unlocked_inner
.config
@ -154,15 +158,6 @@ impl RoutingTable {
.network
.max_connections_per_ip6_prefix_size as usize;
let our_ip_blocks = self
.get_own_peer_info(RoutingDomain::PublicInternet)
.signed_node_info()
.node_info()
.dial_info_detail_list()
.iter()
.map(|did| ip_to_ipblock(ip6_prefix_size, did.dial_info.to_socket_addr().ip()))
.collect::<HashSet<_>>();
move |e: &BucketEntryInner| {
// Ensure this node is not on the local network and is on the public internet
if e.has_node_info(RoutingDomain::LocalNetwork.into()) {
@ -215,11 +210,8 @@ impl RoutingTable {
}
// Exclude any nodes that have our same network block
for did in dids {
let ipblock = ip_to_ipblock(ip6_prefix_size, did.dial_info.to_socket_addr().ip());
if our_ip_blocks.contains(&ipblock) {
return false;
}
if own_node_info.node_is_on_same_ipblock(node_info, ip6_prefix_size) {
return false;
}
true

View File

@ -175,4 +175,21 @@ impl NodeInfo {
}
true
}
/// Does this appear on the same network within the routing domain
pub fn node_is_on_same_ipblock(&self, node_b: &NodeInfo, ip6_prefix_size: usize) -> bool {
let our_ip_blocks = self
.dial_info_detail_list()
.iter()
.map(|did| ip_to_ipblock(ip6_prefix_size, did.dial_info.to_socket_addr().ip()))
.collect::<HashSet<_>>();
for did in node_b.dial_info_detail_list() {
let ipblock = ip_to_ipblock(ip6_prefix_size, did.dial_info.to_socket_addr().ip());
if our_ip_blocks.contains(&ipblock) {
return true;
}
}
false
}
}