diff options
| author | Markus Pettersson <markus.pettersson@mullvad.net> | 2025-07-01 09:22:07 +0200 |
|---|---|---|
| committer | Markus Pettersson <markus.pettersson@mullvad.net> | 2025-07-04 15:31:41 +0200 |
| commit | 846dfb364fcbb4fdc76d6cbad1f09768d6c904c1 (patch) | |
| tree | 222713288e5c0dcabab568115852182b95a5c800 | |
| parent | 1bdd1be3a3c07a5c4fc49489597de0f582085fed (diff) | |
| download | mullvadvpn-846dfb364fcbb4fdc76d6cbad1f09768d6c904c1.tar.xz mullvadvpn-846dfb364fcbb4fdc76d6cbad1f09768d6c904c1.zip | |
Add new ephemeral WinFW policy for blocking until next reboot
Define a new WinFW policy WINFW_CLEANUP_POLICY_BLOCK_UNTIL_REBOOT that
behaves just like WINFW_CLEANUP_POLICY_CONTINUE_BLOCKING, but only
until next reboot.
| -rw-r--r-- | talpid-core/src/firewall/windows/mod.rs | 19 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/winfw.cpp | 56 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/winfw.h | 4 |
3 files changed, 74 insertions, 5 deletions
diff --git a/talpid-core/src/firewall/windows/mod.rs b/talpid-core/src/firewall/windows/mod.rs index 3ef49938dd..4515ba72b7 100644 --- a/talpid-core/src/firewall/windows/mod.rs +++ b/talpid-core/src/firewall/windows/mod.rs @@ -80,7 +80,18 @@ const WINFW_TIMEOUT_SECONDS: u32 = 5; const LOGGING_CONTEXT: &[u8] = b"WinFw\0"; /// The Windows implementation for the firewall. -pub struct Firewall(()); +pub struct Firewall { + /// If firewall rules should even if firewall module is shut down or dies. + /// + /// This should only very cautiously be turned off. + persist: bool, +} + +impl Default for Firewall { + fn default() -> Self { + Self { persist: true } + } +} impl Firewall { pub fn from_args(args: FirewallArguments) -> Result<Self, Error> { @@ -102,7 +113,7 @@ impl Firewall { }; log::trace!("Successfully initialized windows firewall module"); - Ok(Firewall(())) + Ok(Firewall::default()) } fn initialize_blocked( @@ -128,7 +139,7 @@ impl Firewall { consume_and_log_hyperv_err("Add block-all Hyper-V filter", result); }); - Ok(Firewall(())) + Ok(Firewall::default()) } pub fn apply_policy(&mut self, policy: FirewallPolicy) -> Result<(), Error> { @@ -408,6 +419,7 @@ impl Firewall { impl Drop for Firewall { fn drop(&mut self) { + // TODO: If if unsafe { WinFw_Deinitialize(WinFwCleanupPolicy::ContinueBlocking) .into_result() @@ -689,6 +701,7 @@ mod winfw { pub enum WinFwCleanupPolicy { ContinueBlocking = 0, ResetFirewall = 1, + BlockingUntilReboot = 2, } ffi_error!(InitializationResult, Error::Initialization); diff --git a/windows/winfw/src/winfw/winfw.cpp b/windows/winfw/src/winfw/winfw.cpp index c862de4b5a..cd90befead 100644 --- a/windows/winfw/src/winfw/winfw.cpp +++ b/windows/winfw/src/winfw/winfw.cpp @@ -4,6 +4,7 @@ #include "objectpurger.h" #include "mullvadobjects.h" #include "rules/persistent/blockall.h" +#include "rules/baseline/blockall.h" #include "libwfp/ipnetwork.h" #include <windows.h> #include <libcommon/error.h> @@ -167,11 +168,14 @@ WinFw_Deinitialize(WINFW_CLEANUP_POLICY cleanupPolicy) delete g_fwContext; g_fwContext = nullptr; + std::stringstream ss; + ss << "Deinitializing WinFw"; + g_logSink(MULLVAD_LOG_LEVEL_WARNING, ss.str().c_str(), g_logSinkContext); + // - // Continue blocking if this is what the caller requested + // Continue blocking with persistent rules if this is what the caller requested // and if the current policy is "(net) blocked". // - if (WINFW_CLEANUP_POLICY_CONTINUE_BLOCKING == cleanupPolicy && FwContext::Policy::Blocked == activePolicy) { @@ -182,6 +186,10 @@ WinFw_Deinitialize(WINFW_CLEANUP_POLICY cleanupPolicy) rules::persistent::BlockAll blockAll; + std::stringstream ss; + ss << "Adding persistent block rules"; + g_logSink(MULLVAD_LOG_LEVEL_WARNING, ss.str().c_str(), g_logSinkContext); + return sessionController->executeTransaction([&](SessionController &controller, wfp::FilterEngine &engine) { ObjectPurger::GetRemoveNonPersistentFunctor()(engine); @@ -205,6 +213,50 @@ WinFw_Deinitialize(WINFW_CLEANUP_POLICY cleanupPolicy) } } + // + // Continue blocking with non-persistent rules if this is what the caller requested + // and if the current policy is "(net) blocked". + // + if (WINFW_CLEANUP_POLICY_BLOCK_UNTIL_REBOOT == cleanupPolicy + && FwContext::Policy::Blocked == activePolicy) + { + try + { + auto engine = wfp::FilterEngine::StandardSession(DEINITIALIZE_TIMEOUT); + auto sessionController = std::make_unique<SessionController>(std::move(engine)); + + rules::baseline::BlockAll blockAll; + + std::stringstream ss; + ss << "Adding ephemeral block rules"; + g_logSink(MULLVAD_LOG_LEVEL_WARNING, ss.str().c_str(), g_logSinkContext); + + return sessionController->executeTransaction([&](SessionController &controller, wfp::FilterEngine &engine) + { + // Keep non-persistent filters intact, the intent is just to *not* + // persist any filters across a BFE restart, not muck around with + // any other filters. We will apply blocking filters anyway. + ObjectPurger::GetRemovePersistentFunctor()(engine); + + return controller.addProvider(*MullvadObjects::Provider()) + && controller.addSublayer(*MullvadObjects::SublayerBaseline()) + && blockAll.apply(controller); + }); + } + catch (std::exception & err) + { + if (nullptr != g_logSink) + { + g_logSink(MULLVAD_LOG_LEVEL_ERROR, err.what(), g_logSinkContext); + } + return false; + } + catch (...) + { + return false; + } + } + return WINFW_POLICY_STATUS_SUCCESS == WinFw_Reset(); } diff --git a/windows/winfw/src/winfw/winfw.h b/windows/winfw/src/winfw/winfw.h index ab2a136ceb..f40d835a95 100644 --- a/windows/winfw/src/winfw/winfw.h +++ b/windows/winfw/src/winfw/winfw.h @@ -127,6 +127,10 @@ enum WINFW_CLEANUP_POLICY : uint32_t // Remove all objects that have been registered with WFP. WINFW_CLEANUP_POLICY_RESET_FIREWALL = 1, + + // Continue blocking if this is the active policy. + // Adds ephemeral blocking filters that are active until WinFw is shut down (??) + WINFW_CLEANUP_POLICY_BLOCK_UNTIL_REBOOT = 2, }; // |
