diff options
| -rw-r--r-- | windows/winfw/src/winfw/fwcontext.cpp | 107 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/fwcontext.h | 9 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/objectpurger.cpp | 54 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/objectpurger.h | 18 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/sessioncontroller.cpp | 10 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/sessioncontroller.h | 5 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/winfw.vcxproj | 2 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/winfw.vcxproj.filters | 2 |
8 files changed, 183 insertions, 24 deletions
diff --git a/windows/winfw/src/winfw/fwcontext.cpp b/windows/winfw/src/winfw/fwcontext.cpp index 5b56d76f13..3eee15be93 100644 --- a/windows/winfw/src/winfw/fwcontext.cpp +++ b/windows/winfw/src/winfw/fwcontext.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "fwcontext.h" #include "mullvadobjects.h" +#include "objectpurger.h" #include "rules/blockall.h" #include "rules/ifirewallrule.h" #include "rules/permitdhcp.h" @@ -73,6 +74,26 @@ FwContext::FwContext(uint32_t timeout) m_baseline = m_sessionController->checkpoint(); } +FwContext::FwContext(uint32_t timeout, const WinFwSettings &settings) + : m_baseline(0) +{ + auto engine = wfp::FilterEngine::StandardSession(timeout); + + // + // Pass engine ownership to "session controller" + // + m_sessionController = std::make_unique<SessionController>(std::move(engine)); + + uint32_t checkpoint = 0; + + if (false == applyBlockedBaseConfiguration(settings, checkpoint)) + { + throw std::runtime_error("Failed to apply base configuration in BFE."); + } + + m_baseline = checkpoint; +} + bool FwContext::applyPolicyConnecting(const WinFwSettings &settings, const WinFwRelay &relay) { Ruleset ruleset; @@ -122,51 +143,89 @@ bool FwContext::applyPolicyConnected(const WinFwSettings &settings, const WinFwR bool FwContext::applyPolicyBlocked(const WinFwSettings &settings) { + return applyRuleset(composePolicyBlocked(settings)); +} + +bool FwContext::reset() +{ + return m_sessionController->executeTransaction([this](SessionController &controller, wfp::FilterEngine &) + { + return controller.revert(m_baseline), true; + }); +} + +FwContext::Ruleset FwContext::composePolicyBlocked(const WinFwSettings &settings) +{ Ruleset ruleset; AppendNetBlockedRules(ruleset); AppendSettingsRules(ruleset, settings); - return applyRuleset(ruleset); + return ruleset; } -bool FwContext::reset() +bool FwContext::applyBaseConfiguration() { - return m_sessionController->executeTransaction([this]() + return m_sessionController->executeTransaction([this](SessionController &controller, wfp::FilterEngine &engine) { - m_sessionController->revert(m_baseline); - return true; + return applyCommonBaseConfiguration(controller, engine); }); } -bool FwContext::applyRuleset(const Ruleset &ruleset) +bool FwContext::applyBlockedBaseConfiguration(const WinFwSettings &settings, uint32_t &checkpoint) { - return m_sessionController->executeTransaction([&]() + return m_sessionController->executeTransaction([&](SessionController &controller, wfp::FilterEngine &engine) { - m_sessionController->revert(m_baseline); - - for (const auto &rule : ruleset) + if (false == applyCommonBaseConfiguration(controller, engine)) { - if (false == rule->apply(*m_sessionController)) - { - return false; - } + return false; } - return true; + // + // Record the current session state with only structural objects added. + // If we snapshot at a later time we'd accidentally include the blocking policy rules + // in the baseline checkpoint. + // + checkpoint = controller.peekCheckpoint(); + + return applyRulesetDirectly(composePolicyBlocked(settings), controller); }); } -bool FwContext::applyBaseConfiguration() +bool FwContext::applyCommonBaseConfiguration(SessionController &controller, wfp::FilterEngine &engine) { - return m_sessionController->executeTransaction([&]() - { - // - // Install structural objects - // + // + // Since we're using a standard WFP session we can make no assumptions + // about which objects are already installed since before. + // + ObjectPurger::GetRemoveAllFunctor()(engine); - return m_sessionController->addProvider(*MullvadObjects::Provider()) - && m_sessionController->addSublayer(*MullvadObjects::SublayerWhitelist()) - && m_sessionController->addSublayer(*MullvadObjects::SublayerBlacklist()); + // + // Install structural objects + // + return controller.addProvider(*MullvadObjects::Provider()) + && controller.addSublayer(*MullvadObjects::SublayerWhitelist()) + && controller.addSublayer(*MullvadObjects::SublayerBlacklist()); +} + +bool FwContext::applyRuleset(const Ruleset &ruleset) +{ + return m_sessionController->executeTransaction([&](SessionController &controller, wfp::FilterEngine &) + { + controller.revert(m_baseline); + return applyRulesetDirectly(ruleset, controller); }); } + +bool FwContext::applyRulesetDirectly(const Ruleset &ruleset, SessionController &controller) +{ + for (const auto &rule : ruleset) + { + if (false == rule->apply(controller)) + { + return false; + } + } + + return true; +} diff --git a/windows/winfw/src/winfw/fwcontext.h b/windows/winfw/src/winfw/fwcontext.h index 65c45ac539..57911e4d35 100644 --- a/windows/winfw/src/winfw/fwcontext.h +++ b/windows/winfw/src/winfw/fwcontext.h @@ -13,6 +13,9 @@ public: FwContext(uint32_t timeout); + // This ctor applies the "blocked" policy. + FwContext(uint32_t timeout, const WinFwSettings &settings); + bool applyPolicyConnecting(const WinFwSettings &settings, const WinFwRelay &relay); bool applyPolicyConnected(const WinFwSettings &settings, const WinFwRelay &relay, const wchar_t *tunnelInterfaceAlias, const wchar_t *v4DnsHosts, const wchar_t *v6DnsHost); bool applyPolicyBlocked(const WinFwSettings &settings); @@ -26,8 +29,14 @@ private: FwContext(const FwContext &) = delete; FwContext &operator=(const FwContext &) = delete; + Ruleset composePolicyBlocked(const WinFwSettings &settings); + bool applyBaseConfiguration(); + bool applyBlockedBaseConfiguration(const WinFwSettings &settings, uint32_t &checkpoint); + bool applyCommonBaseConfiguration(SessionController &controller, wfp::FilterEngine &engine); + bool applyRuleset(const Ruleset &ruleset); + bool applyRulesetDirectly(const Ruleset &ruleset, SessionController &controller); std::unique_ptr<SessionController> m_sessionController; diff --git a/windows/winfw/src/winfw/objectpurger.cpp b/windows/winfw/src/winfw/objectpurger.cpp new file mode 100644 index 0000000000..b9c6048658 --- /dev/null +++ b/windows/winfw/src/winfw/objectpurger.cpp @@ -0,0 +1,54 @@ +#include "stdafx.h" +#include "objectpurger.h" +#include "mullvadguids.h" +#include "wfpobjecttype.h" +#include "libwfp/filterengine.h" +#include "libwfp/objectdeleter.h" +#include <algorithm> + +namespace +{ + +using ObjectDeleter = std::function<void(wfp::FilterEngine &, const GUID &)>; + +template<typename TRange> +void RemoveRange(wfp::FilterEngine &engine, ObjectDeleter deleter, TRange range) +{ + std::for_each(range.first, range.second, [&](const auto &record) + { + const GUID &objectId = record.second; + deleter(engine, objectId); + }); +} + +} // anonymous namespace + +//static +ObjectPurger::RemovalFunctor ObjectPurger::GetRemoveFiltersFunctor() +{ + return [](wfp::FilterEngine &engine) + { + const auto registry = MullvadGuids::DetailedRegistry(); + + // Resolve correct overload. + void (*deleter)(wfp::FilterEngine &, const GUID &) = wfp::ObjectDeleter::DeleteFilter; + + RemoveRange(engine, deleter, registry.equal_range(WfpObjectType::Filter)); + }; +} + +//static +ObjectPurger::RemovalFunctor ObjectPurger::GetRemoveAllFunctor() +{ + return [](wfp::FilterEngine &engine) + { + const auto registry = MullvadGuids::DetailedRegistry(); + + // Resolve correct overload. + void(*deleter)(wfp::FilterEngine &, const GUID &) = wfp::ObjectDeleter::DeleteFilter; + + RemoveRange(engine, deleter, registry.equal_range(WfpObjectType::Filter)); + RemoveRange(engine, wfp::ObjectDeleter::DeleteSublayer, registry.equal_range(WfpObjectType::Sublayer)); + RemoveRange(engine, wfp::ObjectDeleter::DeleteProvider, registry.equal_range(WfpObjectType::Provider)); + }; +} diff --git a/windows/winfw/src/winfw/objectpurger.h b/windows/winfw/src/winfw/objectpurger.h new file mode 100644 index 0000000000..fa82a86f91 --- /dev/null +++ b/windows/winfw/src/winfw/objectpurger.h @@ -0,0 +1,18 @@ +#pragma once + +#include "winfw.h" +#include "libwfp/filterengine.h" +#include <cstdint> +#include <functional> + +class ObjectPurger +{ +public: + + ObjectPurger() = delete; + + using RemovalFunctor = std::function<void(wfp::FilterEngine &engine)>; + + static RemovalFunctor GetRemoveFiltersFunctor(); + static RemovalFunctor GetRemoveAllFunctor(); +}; diff --git a/windows/winfw/src/winfw/sessioncontroller.cpp b/windows/winfw/src/winfw/sessioncontroller.cpp index 29033db263..f3f948cd44 100644 --- a/windows/winfw/src/winfw/sessioncontroller.cpp +++ b/windows/winfw/src/winfw/sessioncontroller.cpp @@ -227,6 +227,16 @@ uint32_t SessionController::checkpoint() return m_records.back().key(); } +uint32_t SessionController::peekCheckpoint() +{ + if (m_transactionRecords.empty()) + { + return 0; + } + + return m_transactionRecords.back().key(); +} + void SessionController::revert(uint32_t key) { if (false == m_activeTransaction) diff --git a/windows/winfw/src/winfw/sessioncontroller.h b/windows/winfw/src/winfw/sessioncontroller.h index d2b62afc39..243a501083 100644 --- a/windows/winfw/src/winfw/sessioncontroller.h +++ b/windows/winfw/src/winfw/sessioncontroller.h @@ -32,6 +32,11 @@ public: uint32_t checkpoint(); // + // Hack. Read checkpoint while currently inside a transaction. + // + uint32_t peekCheckpoint(); + + // // Purge objects in the stack and return to an earlier state // Use only inside active transaction // diff --git a/windows/winfw/src/winfw/winfw.vcxproj b/windows/winfw/src/winfw/winfw.vcxproj index 3f18edda98..e2db2fd432 100644 --- a/windows/winfw/src/winfw/winfw.vcxproj +++ b/windows/winfw/src/winfw/winfw.vcxproj @@ -22,6 +22,7 @@ <ClCompile Include="dllmain.cpp" /> <ClCompile Include="mullvadguids.cpp" /> <ClCompile Include="mullvadobjects.cpp" /> + <ClCompile Include="objectpurger.cpp" /> <ClCompile Include="rules\blockall.cpp" /> <ClCompile Include="rules\permitdhcp.cpp" /> <ClCompile Include="rules\permitlan.cpp" /> @@ -47,6 +48,7 @@ <ClInclude Include="iobjectinstaller.h" /> <ClInclude Include="mullvadguids.h" /> <ClInclude Include="mullvadobjects.h" /> + <ClInclude Include="objectpurger.h" /> <ClInclude Include="wfpobjecttype.h" /> <ClInclude Include="rules\blockall.h" /> <ClInclude Include="rules\ifirewallrule.h" /> diff --git a/windows/winfw/src/winfw/winfw.vcxproj.filters b/windows/winfw/src/winfw/winfw.vcxproj.filters index 1ff779e93b..8ccdaa4627 100644 --- a/windows/winfw/src/winfw/winfw.vcxproj.filters +++ b/windows/winfw/src/winfw/winfw.vcxproj.filters @@ -36,6 +36,7 @@ <ClCompile Include="rules\permitvpntunnelservice.cpp"> <Filter>rules</Filter> </ClCompile> + <ClCompile Include="objectpurger.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="stdafx.h" /> @@ -79,6 +80,7 @@ </ClInclude> <ClInclude Include="wfpobjecttype.h" /> <ClInclude Include="guidhash.h" /> + <ClInclude Include="objectpurger.h" /> </ItemGroup> <ItemGroup> <Filter Include="rules"> |
