keep network from going down when external ip addresses haven't changed

This commit is contained in:
Christien Rioux 2023-10-11 23:12:54 -04:00
parent 084d4ae98b
commit 54c403ebfb
3 changed files with 80 additions and 7 deletions

View File

@ -39,8 +39,11 @@ struct DiscoveryContextInner {
struct DiscoveryContextUnlockedInner { struct DiscoveryContextUnlockedInner {
routing_table: RoutingTable, routing_table: RoutingTable,
net: Network, net: Network,
clear_network_callback: ClearNetworkCallback,
// per-protocol // per-protocol
intf_addrs: Vec<SocketAddress>, intf_addrs: Vec<SocketAddress>,
existing_external_address: Option<SocketAddress>,
protocol_type: ProtocolType, protocol_type: ProtocolType,
address_type: AddressType, address_type: AddressType,
} }
@ -51,21 +54,45 @@ pub struct DiscoveryContext {
inner: Arc<Mutex<DiscoveryContextInner>>, inner: Arc<Mutex<DiscoveryContextInner>>,
} }
pub type ClearNetworkCallback = Arc<dyn Fn() -> SendPinBoxFuture<()> + Send + Sync>;
impl DiscoveryContext { impl DiscoveryContext {
pub fn new( pub fn new(
routing_table: RoutingTable, routing_table: RoutingTable,
net: Network, net: Network,
protocol_type: ProtocolType, protocol_type: ProtocolType,
address_type: AddressType, address_type: AddressType,
clear_network_callback: ClearNetworkCallback,
) -> Self { ) -> Self {
let intf_addrs = let intf_addrs =
Self::get_local_addresses(routing_table.clone(), protocol_type, address_type); Self::get_local_addresses(routing_table.clone(), protocol_type, address_type);
// Get the existing external address to check to see if it has changed
let existing_dial_info = routing_table.all_filtered_dial_info_details(
RoutingDomain::PublicInternet.into(),
&DialInfoFilter::default()
.with_address_type(address_type)
.with_protocol_type(protocol_type),
);
let existing_external_address = if existing_dial_info.len() == 1 {
Some(
existing_dial_info
.first()
.unwrap()
.dial_info
.socket_address(),
)
} else {
None
};
Self { Self {
unlocked_inner: Arc::new(DiscoveryContextUnlockedInner { unlocked_inner: Arc::new(DiscoveryContextUnlockedInner {
routing_table, routing_table,
net, net,
clear_network_callback,
intf_addrs, intf_addrs,
existing_external_address,
protocol_type, protocol_type,
address_type, address_type,
}), }),
@ -631,6 +658,22 @@ impl DiscoveryContext {
return; return;
} }
// Did external addresses change from the last time we made dialinfo?
let some_clear_network_callback = {
let inner = self.inner.lock();
let ext_1 = inner.external_1.as_ref().unwrap().address;
let ext_2 = inner.external_2.as_ref().unwrap().address;
if (ext_1 != ext_2) || Some(ext_1) != self.unlocked_inner.existing_external_address {
// External address was not found, or has changed, go ahead and clear the network so we can do better
Some(self.unlocked_inner.clear_network_callback.clone())
} else {
None
}
};
if let Some(clear_network_callback) = some_clear_network_callback {
clear_network_callback().await;
}
// UPNP Automatic Mapping // UPNP Automatic Mapping
/////////// ///////////
if enable_upnp { if enable_upnp {

View File

@ -99,6 +99,8 @@ struct NetworkInner {
enable_ipv6_local: bool, enable_ipv6_local: bool,
/// set if we need to calculate our public dial info again /// set if we need to calculate our public dial info again
needs_public_dial_info_check: bool, needs_public_dial_info_check: bool,
/// set if we have yet to clear the network during public dial info checking
network_already_cleared: bool,
/// the punishment closure to enax /// the punishment closure to enax
public_dial_info_check_punishment: Option<Box<dyn FnOnce() + Send + 'static>>, public_dial_info_check_punishment: Option<Box<dyn FnOnce() + Send + 'static>>,
/// udp socket record for bound-first sockets, which are used to guarantee a port is available before /// udp socket record for bound-first sockets, which are used to guarantee a port is available before
@ -148,6 +150,7 @@ impl Network {
network_started: false, network_started: false,
network_needs_restart: false, network_needs_restart: false,
needs_public_dial_info_check: false, needs_public_dial_info_check: false,
network_already_cleared: false,
public_dial_info_check_punishment: None, public_dial_info_check_punishment: None,
protocol_config: Default::default(), protocol_config: Default::default(),
static_public_dialinfo: ProtocolTypeSet::empty(), static_public_dialinfo: ProtocolTypeSet::empty(),

View File

@ -22,7 +22,6 @@ impl Network {
editor.clear_dial_info_details(None, None); editor.clear_dial_info_details(None, None);
editor.set_network_class(Some(NetworkClass::OutboundOnly)); editor.set_network_class(Some(NetworkClass::OutboundOnly));
editor.clear_relay_node();
editor.commit(true).await; editor.commit(true).await;
} }
} }
@ -103,7 +102,7 @@ impl Network {
) -> EyreResult<()> { ) -> EyreResult<()> {
// Figure out if we can optimize TCP/WS checking since they are often on the same port // Figure out if we can optimize TCP/WS checking since they are often on the same port
let (protocol_config, tcp_same_port) = { let (protocol_config, tcp_same_port) = {
let inner = self.inner.lock(); let mut inner = self.inner.lock();
let protocol_config = inner.protocol_config.clone(); let protocol_config = inner.protocol_config.clone();
let tcp_same_port = if protocol_config.inbound.contains(ProtocolType::TCP) let tcp_same_port = if protocol_config.inbound.contains(ProtocolType::TCP)
&& protocol_config.inbound.contains(ProtocolType::WS) && protocol_config.inbound.contains(ProtocolType::WS)
@ -112,6 +111,10 @@ impl Network {
} else { } else {
false false
}; };
// Allow network to be cleared if external addresses change
inner.network_already_cleared = false;
//
(protocol_config, tcp_same_port) (protocol_config, tcp_same_port)
}; };
@ -125,8 +128,7 @@ impl Network {
.into_iter() .into_iter()
.collect(); .collect();
// Clear public dialinfo and network class in prep for discovery // Set most permissive network config
let mut editor = self let mut editor = self
.routing_table() .routing_table()
.edit_routing_domain(RoutingDomain::PublicInternet); .edit_routing_domain(RoutingDomain::PublicInternet);
@ -136,10 +138,29 @@ impl Network {
protocol_config.family_global, protocol_config.family_global,
protocol_config.public_internet_capabilities.clone(), protocol_config.public_internet_capabilities.clone(),
); );
editor.commit(true).await;
// Create a callback to clear the network if we need to 'start over'
let this = self.clone();
let clear_network_callback: ClearNetworkCallback = Arc::new(move || {
let this = this.clone();
Box::pin(async move {
// Ensure we only do this once per network class discovery
{
let mut inner = this.inner.lock();
if inner.network_already_cleared {
return;
}
inner.network_already_cleared = true;
}
let mut editor = this
.routing_table()
.edit_routing_domain(RoutingDomain::PublicInternet);
editor.clear_dial_info_details(None, None); editor.clear_dial_info_details(None, None);
editor.set_network_class(None); editor.set_network_class(None);
editor.clear_relay_node();
editor.commit(true).await; editor.commit(true).await;
})
});
// Process all protocol and address combinations // Process all protocol and address combinations
let mut unord = FuturesUnordered::new(); let mut unord = FuturesUnordered::new();
@ -152,6 +173,7 @@ impl Network {
self.clone(), self.clone(),
ProtocolType::UDP, ProtocolType::UDP,
AddressType::IPV4, AddressType::IPV4,
clear_network_callback.clone(),
); );
udpv4_context udpv4_context
.discover(&mut unord) .discover(&mut unord)
@ -166,6 +188,7 @@ impl Network {
self.clone(), self.clone(),
ProtocolType::UDP, ProtocolType::UDP,
AddressType::IPV6, AddressType::IPV6,
clear_network_callback.clone(),
); );
udpv6_context udpv6_context
.discover(&mut unord) .discover(&mut unord)
@ -182,6 +205,7 @@ impl Network {
self.clone(), self.clone(),
ProtocolType::TCP, ProtocolType::TCP,
AddressType::IPV4, AddressType::IPV4,
clear_network_callback.clone(),
); );
tcpv4_context tcpv4_context
.discover(&mut unord) .discover(&mut unord)
@ -195,6 +219,7 @@ impl Network {
self.clone(), self.clone(),
ProtocolType::WS, ProtocolType::WS,
AddressType::IPV4, AddressType::IPV4,
clear_network_callback.clone(),
); );
wsv4_context wsv4_context
.discover(&mut unord) .discover(&mut unord)
@ -211,6 +236,7 @@ impl Network {
self.clone(), self.clone(),
ProtocolType::TCP, ProtocolType::TCP,
AddressType::IPV6, AddressType::IPV6,
clear_network_callback.clone(),
); );
tcpv6_context tcpv6_context
.discover(&mut unord) .discover(&mut unord)
@ -225,6 +251,7 @@ impl Network {
self.clone(), self.clone(),
ProtocolType::WS, ProtocolType::WS,
AddressType::IPV6, AddressType::IPV6,
clear_network_callback.clone(),
); );
wsv6_context wsv6_context
.discover(&mut unord) .discover(&mut unord)