summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--windows/winfw/src/winfw/fwcontext.cpp107
-rw-r--r--windows/winfw/src/winfw/fwcontext.h9
-rw-r--r--windows/winfw/src/winfw/objectpurger.cpp54
-rw-r--r--windows/winfw/src/winfw/objectpurger.h18
-rw-r--r--windows/winfw/src/winfw/sessioncontroller.cpp10
-rw-r--r--windows/winfw/src/winfw/sessioncontroller.h5
-rw-r--r--windows/winfw/src/winfw/winfw.vcxproj2
-rw-r--r--windows/winfw/src/winfw/winfw.vcxproj.filters2
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">