diff --git a/Cargo.lock b/Cargo.lock index c2b7dfe6cc..16a2bcd946 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -387,9 +387,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.16.2" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" dependencies = [ "aws-lc-sys", "zeroize", @@ -397,9 +397,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.39.1" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" +checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" dependencies = [ "cc", "cmake", @@ -833,9 +833,9 @@ checksum = "bba18ee93d577a8428902687bcc2b6b45a56b1981a1f6d779731c86cc4c5db18" [[package]] name = "clap" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -855,9 +855,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -963,7 +963,7 @@ dependencies = [ "base64 0.22.1", "hkdf", "percent-encoding", - "rand 0.8.5", + "rand 0.8.6", "sha2", "subtle", "time", @@ -1331,7 +1331,7 @@ dependencies = [ "matches", "model_derive", "openidconnect", - "rand 0.8.5", + "rand 0.8.6", "reqwest", "rsa", "secrecy", @@ -1391,7 +1391,7 @@ dependencies = [ "paste", "pgp", "prost", - "rand 0.8.5", + "rand 0.8.6", "regex", "reqwest", "rsa", @@ -1501,7 +1501,7 @@ dependencies = [ "clap", "defguard_common", "defguard_core", - "rand 0.8.5", + "rand 0.8.6", "sqlx", "tokio", "tracing", @@ -1580,7 +1580,7 @@ dependencies = [ "jsonwebkey", "jsonwebtoken", "openidconnect", - "rand 0.8.5", + "rand 0.8.6", "reqwest", "rsa", "semver", @@ -3194,7 +3194,7 @@ dependencies = [ "p256", "p384", "pem", - "rand 0.8.5", + "rand 0.8.6", "rsa", "serde", "serde_json", @@ -3702,7 +3702,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "serde", "smallvec", "zeroize", @@ -3807,7 +3807,7 @@ dependencies = [ "chrono", "getrandom 0.2.17", "http", - "rand 0.8.5", + "rand 0.8.6", "reqwest", "serde", "serde_json", @@ -4041,7 +4041,7 @@ dependencies = [ "oauth2", "p256", "p384", - "rand 0.8.5", + "rand 0.8.6", "rsa", "serde", "serde-value", @@ -4374,7 +4374,7 @@ dependencies = [ "p256", "p384", "p521", - "rand 0.8.5", + "rand 0.8.6", "regex", "replace_with", "ripemd", @@ -4418,7 +4418,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -4712,9 +4712,9 @@ dependencies = [ [[package]] name = "pxfm" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" +checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" [[package]] name = "qoi" @@ -4830,9 +4830,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -5680,6 +5680,16 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + [[package]] name = "signature" version = "2.2.0" @@ -5917,7 +5927,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand 0.8.5", + "rand 0.8.6", "rsa", "serde", "sha1", @@ -5958,7 +5968,7 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand 0.8.5", + "rand 0.8.6", "serde", "serde_json", "sha2", @@ -6229,7 +6239,7 @@ dependencies = [ "percent-encoding", "pest", "pest_derive", - "rand 0.8.5", + "rand 0.8.6", "regex", "serde", "serde_json", @@ -6369,15 +6379,16 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.52.0" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91135f59b1cbf38c91e73cf3386fca9bb77915c45ce2771460c9d92f0f3d776" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ "bytes", "libc", "mio", "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.61.2", @@ -6894,9 +6905,9 @@ checksum = "e2eebbbfe4093922c2b6734d7c679ebfebd704a0d7e56dfcb0d05818ce28977d" [[package]] name = "uuid" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -7257,9 +7268,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" dependencies = [ "rustls-pki-types", ] diff --git a/Cargo.toml b/Cargo.toml index 73416b02ba..e59620bd38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -114,6 +114,7 @@ tokio = { version = "1", features = [ "macros", "parking_lot", "rt-multi-thread", + "signal", "sync", "time", ] } diff --git a/crates/defguard/src/main.rs b/crates/defguard/src/main.rs index 2d45e63ba9..508e76eff1 100644 --- a/crates/defguard/src/main.rs +++ b/crates/defguard/src/main.rs @@ -3,6 +3,7 @@ use std::{ sync::{Arc, Mutex, RwLock}, }; +use anyhow::bail; use bytes::Bytes; use defguard_common::{ VERSION, @@ -46,9 +47,12 @@ use defguard_setup::{ }; use defguard_vpn_stats_purge::run_periodic_stats_purge; use secrecy::ExposeSecret; -use tokio::sync::{ - broadcast, - mpsc::{channel, unbounded_channel}, +use tokio::{ + signal::ctrl_c, + sync::{ + broadcast, + mpsc::{channel, unbounded_channel}, + }, }; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; @@ -135,7 +139,7 @@ async fn main() -> Result<(), anyhow::Error> { // Both flags must be provided together if let Err(msg) = config.validate_adopt_flags() { - anyhow::bail!("{msg}"); + bail!(msg); } let has_auto_adopt_flags = config.adopt_edge.is_some() && config.adopt_gateway.is_some(); @@ -158,7 +162,7 @@ async fn main() -> Result<(), anyhow::Error> { run_setup_web_server(pool.clone(), config.http_bind_address, config.http_port) .await { - anyhow::bail!("Setup web server exited with error: {err}"); + bail!("Setup web server exited with error: {err}"); } } ActiveWizard::Migration => { @@ -172,7 +176,7 @@ async fn main() -> Result<(), anyhow::Error> { ) .await { - anyhow::bail!("Migration web server exited with error: {err}"); + bail!("Migration web server exited with error: {err}"); } } } @@ -213,7 +217,7 @@ async fn main() -> Result<(), anyhow::Error> { let certs = Certificates::get_or_default(&pool).await?; if certs.ca_cert_der.is_none() || certs.ca_key_der.is_none() { - anyhow::bail!("CA certificate or key were not found, despite completing setup.") + bail!("CA certificate or key were not found, despite completing setup.") } // read grpc TLS cert and key from legacy config values @@ -258,14 +262,14 @@ async fn main() -> Result<(), anyhow::Error> { // run services tokio::select! { - res = proxy_manager.run() => error!("ProxyManager returned early: {res:?}"), - res = gateway_manager.run() => error!("GatewayManager returned early: {res:?}"), + res = proxy_manager.run() => bail!("ProxyManager returned early: {res:?}"), + res = gateway_manager.run() => bail!("GatewayManager returned early: {res:?}"), res = run_grpc_server( Arc::clone(&worker_state), pool.clone(), grpc_cert, grpc_key, - ) => error!("gRPC server returned early: {res:?}"), + ) => bail!("gRPC server returned early: {res:?}"), res = run_web_server( worker_state, webhook_tx, @@ -277,17 +281,17 @@ async fn main() -> Result<(), anyhow::Error> { api_event_tx, incompatible_components, proxy_control_tx.clone() - ) => error!("Web server returned early: {res:?}"), + ) => bail!("Web server returned early: {res:?}"), res = run_periodic_stats_purge( pool.clone(), settings.stats_purge_frequency(), settings.stats_purge_threshold() ), if settings.enable_stats_purge => - error!("Periodic stats purge task returned early: {res:?}"), + bail!("Periodic stats purge task returned early: {res:?}"), res = run_periodic_license_check(&pool, proxy_control_tx) => - error!("Periodic license check task returned early: {res:?}"), + bail!("Periodic license check task returned early: {res:?}"), res = run_utility_thread(&pool, gateway_tx.clone()) => - error!("Utility thread returned early: {res:?}"), + bail!("Utility thread returned early: {res:?}"), res = run_event_router( RouterReceiverSet::new( api_event_rx, @@ -297,21 +301,20 @@ async fn main() -> Result<(), anyhow::Error> { event_logger_tx, gateway_tx.clone(), activity_log_stream_reload_notify.clone() - ) => error!("Event router returned early: {res:?}"), + ) => bail!("Event router returned early: {res:?}"), res = run_event_logger(pool.clone(), event_logger_rx, activity_log_messages_tx.clone()) => - error!("Activity log event logger returned early: {res:?}"), + bail!("Activity log event logger returned early: {res:?}"), res = run_activity_log_stream_manager( pool.clone(), activity_log_stream_reload_notify.clone(), activity_log_messages_rx - ) => error!("Activity log stream manager returned early: {res:?}"), + ) => bail!("Activity log stream manager returned early: {res:?}"), res = run_session_manager( pool.clone(), peer_stats_rx, session_manager_event_tx, gateway_tx - ) => error!("VPN client session manager returned early: {res:?}"), + ) => bail!("VPN client session manager returned early: {res:?}"), + _ = ctrl_c() => Ok(()), } - - Ok(()) } diff --git a/crates/defguard_core/src/enterprise/activity_log_stream/activity_log_stream_manager.rs b/crates/defguard_core/src/enterprise/activity_log_stream/activity_log_stream_manager.rs index e1a2a467b4..0588987a89 100644 --- a/crates/defguard_core/src/enterprise/activity_log_stream/activity_log_stream_manager.rs +++ b/crates/defguard_core/src/enterprise/activity_log_stream/activity_log_stream_manager.rs @@ -13,8 +13,8 @@ use crate::enterprise::{ is_business_license_active, }; -// check if enterprise features are enabled every minute -const ENTERPRISE_CHECK_PERIOD_SECS: u64 = 60; +// Every minute, check if enterprise features are enabled. +const ENTERPRISE_CHECK_PERIOD: Duration = Duration::from_secs(60); #[instrument(skip_all)] pub async fn run_activity_log_stream_manager( @@ -24,7 +24,7 @@ pub async fn run_activity_log_stream_manager( ) -> anyhow::Result<()> { info!("Starting activity log stream manager"); - let mut enterprise_check_timer = interval(Duration::from_secs(ENTERPRISE_CHECK_PERIOD_SECS)); + let mut enterprise_check_timer = interval(ENTERPRISE_CHECK_PERIOD); // initialize enterprise features status let mut enterprise_features_enabled = is_business_license_active(); @@ -76,7 +76,8 @@ pub async fn run_activity_log_stream_manager( } } else { info!( - "Activity log stream manager cannot start streams, license needs enterprise features enabled." + "Activity log stream manager cannot start streams, license needs enterprise \ + features enabled." ); } @@ -88,7 +89,8 @@ pub async fn run_activity_log_stream_manager( tokio::select! { () = notification.notified() => { info!( - "Activity log stream manager configuration refresh notification received, reloading streaming tasks." + "Activity log stream manager configuration refresh notification received, \ + reloading streaming tasks." ); break; } @@ -96,13 +98,15 @@ pub async fn run_activity_log_stream_manager( // check if enterprise features status has changed let current_enterprise_features_enabled = is_business_license_active(); if current_enterprise_features_enabled != enterprise_features_enabled { - warn!("Activity log stream manager will reload, detected license enterprise features status has changed"); + warn!("Activity log stream manager will reload, detected license \ + enterprise features status has changed"); enterprise_features_enabled = current_enterprise_features_enabled; break; } } task_output = handles.join_next(), if !handles.is_empty() => { - error!("Activity log streaming task has terminated early with result: {task_output:?}, reloading activity log stream manager"); + error!("Activity log streaming task has terminated early with result: \ + {task_output:?}, reloading activity log stream manager"); break; } } diff --git a/crates/defguard_event_logger/src/lib.rs b/crates/defguard_event_logger/src/lib.rs index 237dbdf53b..5157fc1ca9 100644 --- a/crates/defguard_event_logger/src/lib.rs +++ b/crates/defguard_event_logger/src/lib.rs @@ -100,7 +100,7 @@ pub async fn run_event_logger( // Receive messages in an infinite loop loop { // Collect multiple messages from the channel (up to MESSAGE_LIMIT at a time) - let mut message_buffer: Vec = Vec::with_capacity(MESSAGE_LIMIT); + let mut message_buffer = Vec::with_capacity(MESSAGE_LIMIT); let message_count = event_logger_rx .recv_many(&mut message_buffer, MESSAGE_LIMIT) .await; diff --git a/crates/defguard_session_manager/src/lib.rs b/crates/defguard_session_manager/src/lib.rs index f1f94c4a9d..88ad9862a0 100644 --- a/crates/defguard_session_manager/src/lib.rs +++ b/crates/defguard_session_manager/src/lib.rs @@ -31,7 +31,7 @@ pub mod events; pub mod session_state; const MESSAGE_LIMIT: usize = 100; -pub const SESSION_UPDATE_INTERVAL: u64 = 60; +pub const SESSION_UPDATE_INTERVAL: Duration = Duration::from_secs(60); pub enum IterationOutcome { ProcessedBatch(usize), @@ -45,7 +45,7 @@ pub async fn run_session_manager( gateway_tx: Sender, ) -> Result<(), SessionManagerError> { info!("Starting VPN client session manager service"); - let mut session_update_timer = interval(Duration::from_secs(SESSION_UPDATE_INTERVAL)); + let mut session_update_timer = interval(SESSION_UPDATE_INTERVAL); // initialize session manager let mut session_manager = SessionManager::new(pool, session_manager_event_tx, gateway_tx); @@ -65,15 +65,16 @@ pub async fn run_session_manager_iteration( peer_stats_rx: &mut UnboundedReceiver, session_update_timer: &mut Interval, ) -> Result { - // receive next batch of peer stats messages - // if no message is received within `SESSION_UPDATE_INTERVAL` trigger session status refresh anyway - // to disconnect inactive sessions if necessary - let mut message_buffer: Vec = Vec::with_capacity(MESSAGE_LIMIT); + // Receive next batch of peer stats messages. If no message is received within + // `SESSION_UPDATE_INTERVAL`, trigger session status refresh anyway to disconnect inactive + // sessions, if necessary. + let mut message_buffer = Vec::with_capacity(MESSAGE_LIMIT); let message_count = tokio::select! { biased; message_count = peer_stats_rx.recv_many(&mut message_buffer, MESSAGE_LIMIT) => message_count, _ = session_update_timer.tick() => { - debug!("No WireGuard peer stats updates received in last {SESSION_UPDATE_INTERVAL}. Triggering session status update to disconnect inactive clients."); + debug!("No WireGuard peer stats updates received in last {SESSION_UPDATE_INTERVAL:?}. \ + Triggering session status update to disconnect inactive clients."); session_manager.update_inactive_session_status().await?; return Ok(IterationOutcome::TickNoMessages); diff --git a/crates/defguard_session_manager/tests/common/mod.rs b/crates/defguard_session_manager/tests/common/mod.rs index 792cd2b74d..80e50ce253 100644 --- a/crates/defguard_session_manager/tests/common/mod.rs +++ b/crates/defguard_session_manager/tests/common/mod.rs @@ -23,7 +23,7 @@ use defguard_session_manager::{ run_session_manager_iteration, }; use ipnetwork::IpNetwork; -use sqlx::{PgExecutor, query, query_scalar}; +use sqlx::{PgExecutor, PgPool, query, query_scalar}; use tokio::{ sync::{ broadcast, @@ -64,7 +64,7 @@ pub(crate) fn assert_no_gateway_events(harness: &mut SessionManagerHarness) { } impl SessionManagerHarness { - pub(crate) fn new(pool: sqlx::PgPool) -> Self { + pub(crate) fn new(pool: PgPool) -> Self { let (stats_tx, stats_rx) = mpsc::unbounded_channel(); let (event_tx, event_rx) = mpsc::unbounded_channel(); let (gateway_tx, gateway_rx) = broadcast::channel(16); @@ -90,7 +90,7 @@ impl SessionManagerHarness { } pub(crate) async fn run_iteration(&mut self) -> IterationOutcome { - let mut session_update_timer = interval(Duration::from_secs(SESSION_UPDATE_INTERVAL)); + let mut session_update_timer = interval(SESSION_UPDATE_INTERVAL); run_session_manager_iteration( &mut self.manager, &mut self.stats_rx, @@ -112,12 +112,12 @@ impl SessionManagerHarness { } } -pub(crate) async fn create_location(pool: &sqlx::PgPool) -> WireguardNetwork { +pub(crate) async fn create_location(pool: &PgPool) -> WireguardNetwork { create_location_with_mfa_mode(pool, LocationMfaMode::Disabled).await } pub(crate) async fn create_location_with_mfa_mode( - pool: &sqlx::PgPool, + pool: &PgPool, location_mfa_mode: LocationMfaMode, ) -> WireguardNetwork { WireguardNetwork::new( @@ -139,7 +139,7 @@ pub(crate) async fn create_location_with_mfa_mode( .expect("failed to create WireGuard location") } -pub(crate) async fn create_user(pool: &sqlx::PgPool) -> User { +pub(crate) async fn create_user(pool: &PgPool) -> User { User::new( "session-test", Some("pass123"), @@ -153,12 +153,12 @@ pub(crate) async fn create_user(pool: &sqlx::PgPool) -> User { .expect("failed to create user") } -pub(crate) async fn create_device(pool: &sqlx::PgPool, user_id: Id) -> Device { +pub(crate) async fn create_device(pool: &PgPool, user_id: Id) -> Device { create_device_with_pubkey(pool, user_id, "device-pubkey-test").await } pub(crate) async fn create_device_with_pubkey( - pool: &sqlx::PgPool, + pool: &PgPool, user_id: Id, wireguard_pubkey: &str, ) -> Device { @@ -175,7 +175,7 @@ pub(crate) async fn create_device_with_pubkey( .expect("failed to create device") } -pub(crate) async fn attach_device_to_location(pool: &sqlx::PgPool, location_id: Id, device_id: Id) { +pub(crate) async fn attach_device_to_location(pool: &PgPool, location_id: Id, device_id: Id) { let network_device = WireguardNetworkDevice::new( location_id, device_id, @@ -188,7 +188,7 @@ pub(crate) async fn attach_device_to_location(pool: &sqlx::PgPool, location_id: } pub(crate) async fn create_gateway( - pool: &sqlx::PgPool, + pool: &PgPool, location_id: Id, modified_by: String, ) -> Gateway { @@ -196,7 +196,7 @@ pub(crate) async fn create_gateway( } pub(crate) async fn create_gateway_named( - pool: &sqlx::PgPool, + pool: &PgPool, location_id: Id, modified_by: String, name: &str, @@ -214,7 +214,7 @@ pub(crate) async fn create_gateway_named( } pub(crate) async fn authorize_device_in_location( - pool: &sqlx::PgPool, + pool: &PgPool, location_id: Id, user_id: Id, device_id: Id, @@ -274,7 +274,7 @@ pub(crate) fn stale_session_timestamp(location: &WireguardNetwork) -> NaiveD } pub(crate) async fn create_session( - pool: &sqlx::PgPool, + pool: &PgPool, location_id: Id, user_id: Id, device_id: Id, @@ -293,7 +293,7 @@ pub(crate) async fn create_session( #[allow(clippy::too_many_arguments)] pub(crate) async fn create_session_stats( - pool: &sqlx::PgPool, + pool: &PgPool, session_id: Id, gateway_id: Id, collected_at: NaiveDateTime, diff --git a/defguard.service b/defguard.service index 6e36c0040d..3ae5812cac 100644 --- a/defguard.service +++ b/defguard.service @@ -1,5 +1,5 @@ [Unit] -Description=defguard core service +Description=Defguard Core service Documentation=https://docs.defguard.net/ Wants=network-online.target After=network-online.target @@ -14,7 +14,7 @@ KillSignal=SIGINT LimitNOFILE=65536 LimitNPROC=infinity Restart=on-failure -RestartSec=2 +RestartSec=3 TasksMax=infinity OOMScoreAdjust=-1000