diff --git a/gateway/src/node/internal_service_providers/authenticator/error.rs b/gateway/src/node/internal_service_providers/authenticator/error.rs index 5bdde15919..8f5de74508 100644 --- a/gateway/src/node/internal_service_providers/authenticator/error.rs +++ b/gateway/src/node/internal_service_providers/authenticator/error.rs @@ -85,6 +85,9 @@ pub enum AuthenticatorError { #[error("peers can't be interacted with anymore")] PeerInteractionStopped, + #[error("peers interaction timed out while attempting to {operation}")] + PeerInteractionTimeout { operation: &'static str }, + #[error("unknown version number")] UnknownVersion, diff --git a/gateway/src/node/internal_service_providers/authenticator/mixnet_listener.rs b/gateway/src/node/internal_service_providers/authenticator/mixnet_listener.rs index c05d9d8cd6..f0734c63b7 100644 --- a/gateway/src/node/internal_service_providers/authenticator/mixnet_listener.rs +++ b/gateway/src/node/internal_service_providers/authenticator/mixnet_listener.rs @@ -185,11 +185,16 @@ impl MixnetListener { ) -> AuthenticatorHandleResult { let remote_public = init_message.pub_key(); let nonce: u64 = fastrand::u64(..); - let mut registered_and_free = self.registered_and_free.write().await; - if let Some(registration_data) = registered_and_free - .registration_in_progres - .get(&remote_public) - { + + let pending_registration = { + let registered_and_free = self.registered_and_free.read().await; + registered_and_free + .registration_in_progres + .get(&remote_public) + .cloned() + }; + + if let Some(registration_data) = pending_registration { let gateway_data = registration_data.gateway_data.clone(); let bytes = match AuthenticatorVersion::from(protocol) { AuthenticatorVersion::V1 => { @@ -292,7 +297,17 @@ impl MixnetListener { return Ok((bytes, reply_to)); } - let peer = self.peer_manager.query_peer(remote_public).await?; + let peer = match self.peer_manager.query_peer(remote_public).await { + Ok(peer) => peer, + Err(err) => { + tracing::warn!( + "Failed to query peer {}: {err}. Continuing with fresh registration", + remote_public + ); + None + } + }; + if let Some(peer) = peer { let allowed_ipv4 = peer .allowed_ips @@ -383,6 +398,7 @@ impl MixnetListener { return Ok((bytes, reply_to)); } + let mut registered_and_free = self.registered_and_free.write().await; let private_ip_ref = registered_and_free .free_private_network_ips .iter_mut() @@ -818,7 +834,7 @@ impl MixnetListener { .to_bytes() .map_err(AuthenticatorError::response_serialisation)?, AuthenticatorVersion::V1 | AuthenticatorVersion::V2 | AuthenticatorVersion::UNKNOWN => { - return Err(AuthenticatorError::UnknownVersion) + return Err(AuthenticatorError::UnknownVersion); } }; diff --git a/gateway/src/node/internal_service_providers/authenticator/peer_manager.rs b/gateway/src/node/internal_service_providers/authenticator/peer_manager.rs index c057dfa57c..bf424cdf99 100644 --- a/gateway/src/node/internal_service_providers/authenticator/peer_manager.rs +++ b/gateway/src/node/internal_service_providers/authenticator/peer_manager.rs @@ -8,6 +8,9 @@ use nym_credential_verification::{ClientBandwidth, TicketVerifier}; use nym_credentials_interface::CredentialSpendingData; use nym_wireguard::{peer_controller::PeerControlRequest, WireguardGatewayData}; use nym_wireguard_types::PeerPublicKey; +use tokio::time::{timeout, Duration}; + +const PEER_MANAGER_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5); pub struct PeerManager { pub(crate) wireguard_gateway_data: WireguardGatewayData, @@ -28,9 +31,8 @@ impl PeerManager { .await .map_err(|_| AuthenticatorError::PeerInteractionStopped)?; - response_rx - .await - .map_err(|_| AuthenticatorError::InternalError("no response for add peer".to_string()))? + recv_with_timeout(response_rx, "add peer") + .await? .map_err(|err| { AuthenticatorError::InternalError(format!( "adding peer could not be performed: {err:?}" @@ -48,11 +50,8 @@ impl PeerManager { .await .map_err(|_| AuthenticatorError::PeerInteractionStopped)?; - response_rx - .await - .map_err(|_| { - AuthenticatorError::InternalError("no response for remove peer".to_string()) - })? + recv_with_timeout(response_rx, "remove peer") + .await? .map_err(|err| { AuthenticatorError::InternalError(format!( "removing peer could not be performed: {err:?}" @@ -73,11 +72,8 @@ impl PeerManager { .await .map_err(|_| AuthenticatorError::PeerInteractionStopped)?; - response_rx - .await - .map_err(|_| { - AuthenticatorError::InternalError("no response for query peer".to_string()) - })? + recv_with_timeout(response_rx, "query peer") + .await? .map_err(|err| { AuthenticatorError::InternalError(format!( "querying peer could not be performed: {err:?}" @@ -106,13 +102,8 @@ impl PeerManager { .await .map_err(|_| AuthenticatorError::PeerInteractionStopped)?; - response_rx - .await - .map_err(|_| { - AuthenticatorError::InternalError( - "no response for query client bandwidth".to_string(), - ) - })? + recv_with_timeout(response_rx, "query client bandwidth") + .await? .map_err(|err| { AuthenticatorError::InternalError(format!( "querying client bandwidth could not be performed: {err:?}" @@ -138,11 +129,8 @@ impl PeerManager { .await .map_err(|_| AuthenticatorError::PeerInteractionStopped)?; - response_rx - .await - .map_err(|_| { - AuthenticatorError::InternalError("no response for query verifier".to_string()) - })? + recv_with_timeout(response_rx, "query verifier") + .await? .map_err(|err| { AuthenticatorError::InternalError(format!( "querying verifier could not be performed: {err:?}" @@ -151,6 +139,16 @@ impl PeerManager { } } +async fn recv_with_timeout( + response_rx: oneshot::Receiver, + operation: &'static str, +) -> Result { + timeout(PEER_MANAGER_RESPONSE_TIMEOUT, response_rx) + .await + .map_err(|_| AuthenticatorError::PeerInteractionTimeout { operation })? + .map_err(|_| AuthenticatorError::PeerInteractionStopped) +} + #[cfg(test)] mod tests { use std::{str::FromStr, sync::Arc};