summaryrefslogtreecommitdiffhomepage
path: root/windows
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-12-07 20:31:40 +0100
committerDavid Lönnhager <david.l@mullvad.net>2021-01-04 16:50:18 +0100
commitd9baa6bf9d98858d9f5bae95740b9d5ecb192c0f (patch)
tree1ce85578b7bb8ca1dddad78120231a1c28113146 /windows
parent07d363b919ee0c9e33f444475361194a29f37216 (diff)
downloadmullvadvpn-d9baa6bf9d98858d9f5bae95740b9d5ecb192c0f.tar.xz
mullvadvpn-d9baa6bf9d98858d9f5bae95740b9d5ecb192c0f.zip
Unblock API endpoint while connecting or blocked
Diffstat (limited to 'windows')
-rw-r--r--windows/winfw/src/extras/cli/commands/winfw/policy.cpp4
-rw-r--r--windows/winfw/src/winfw/fwcontext.cpp64
-rw-r--r--windows/winfw/src/winfw/fwcontext.h19
-rw-r--r--windows/winfw/src/winfw/mullvadguids.cpp15
-rw-r--r--windows/winfw/src/winfw/mullvadguids.h2
-rw-r--r--windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp87
-rw-r--r--windows/winfw/src/winfw/rules/baseline/permitendpoint.h36
-rw-r--r--windows/winfw/src/winfw/winfw.cpp28
-rw-r--r--windows/winfw/src/winfw/winfw.h15
-rw-r--r--windows/winfw/src/winfw/winfw.vcxproj2
-rw-r--r--windows/winfw/src/winfw/winfw.vcxproj.filters6
11 files changed, 245 insertions, 33 deletions
diff --git a/windows/winfw/src/extras/cli/commands/winfw/policy.cpp b/windows/winfw/src/extras/cli/commands/winfw/policy.cpp
index a722501832..7f5b9d980c 100644
--- a/windows/winfw/src/extras/cli/commands/winfw/policy.cpp
+++ b/windows/winfw/src/extras/cli/commands/winfw/policy.cpp
@@ -26,9 +26,9 @@ WinFwProtocol TranslateProtocol(const std::wstring &protocol)
return (0 == _wcsicmp(protocol.c_str(), L"tcp") ? WinFwProtocol::Tcp : WinFwProtocol::Udp);
}
-WinFwRelay CreateRelay(const wchar_t *ip, const std::wstring &port, const std::wstring &protocol)
+WinFwEndpoint CreateRelay(const wchar_t *ip, const std::wstring &port, const std::wstring &protocol)
{
- WinFwRelay r;
+ WinFwEndpoint r;
r.ip = ip;
r.port = common::string::LexicalCast<uint16_t>(port);
diff --git a/windows/winfw/src/winfw/fwcontext.cpp b/windows/winfw/src/winfw/fwcontext.cpp
index b8959cfc01..99a3d3dc26 100644
--- a/windows/winfw/src/winfw/fwcontext.cpp
+++ b/windows/winfw/src/winfw/fwcontext.cpp
@@ -15,6 +15,7 @@
#include "rules/baseline/permitvpntunnelservice.h"
#include "rules/baseline/permitping.h"
#include "rules/baseline/permitdns.h"
+#include "rules/baseline/permitendpoint.h"
#include "rules/dns/blockall.h"
#include "rules/dns/permittunnel.h"
#include "rules/dns/permitnontunnel.h"
@@ -43,6 +44,19 @@ multi::PermitVpnRelay::Protocol TranslateProtocol(WinFwProtocol protocol)
};
}
+baseline::PermitEndpoint::Protocol TranslateEndpointProtocol(WinFwProtocol protocol)
+{
+ switch (protocol)
+ {
+ case Tcp: return baseline::PermitEndpoint::Protocol::Tcp;
+ case Udp: return baseline::PermitEndpoint::Protocol::Udp;
+ default:
+ {
+ THROW_ERROR("Missing case handler in switch clause");
+ }
+ };
+}
+
//
// Since the PermitLan rule doesn't specifically address DNS, it will allow DNS requests targetting
// a local resolver to leave the machine. From the local resolver the request will either be
@@ -91,7 +105,7 @@ void AppendSettingsRules
void AppendRelayRules
(
FwContext::Ruleset &ruleset,
- const WinFwRelay &relay,
+ const WinFwEndpoint &relay,
const std::wstring &relayClient
)
{
@@ -111,6 +125,22 @@ void AppendRelayRules
));
}
+//
+// Refer comment on `AppendSettingsRules`.
+//
+void AppendAllowedEndpointRules
+(
+ FwContext::Ruleset &ruleset,
+ const WinFwEndpoint &endpoint
+)
+{
+ ruleset.emplace_back(std::make_unique<baseline::PermitEndpoint>(
+ wfp::IpAddress(endpoint.ip),
+ endpoint.port,
+ TranslateEndpointProtocol(endpoint.protocol)
+ ));
+}
+
void AppendNetBlockedRules(FwContext::Ruleset &ruleset)
{
ruleset.emplace_back(std::make_unique<baseline::BlockAll>());
@@ -145,7 +175,8 @@ FwContext::FwContext
FwContext::FwContext
(
uint32_t timeout,
- const WinFwSettings &settings
+ const WinFwSettings &settings,
+ const std::optional<WinFwEndpoint> &allowedEndpoint
)
: m_baseline(0)
, m_activePolicy(Policy::None)
@@ -159,7 +190,7 @@ FwContext::FwContext
uint32_t checkpoint = 0;
- if (false == applyBlockedBaseConfiguration(settings, checkpoint))
+ if (false == applyBlockedBaseConfiguration(settings, allowedEndpoint, checkpoint))
{
THROW_ERROR("Failed to apply base configuration in BFE");
}
@@ -171,9 +202,10 @@ FwContext::FwContext
bool FwContext::applyPolicyConnecting
(
const WinFwSettings &settings,
- const WinFwRelay &relay,
+ const WinFwEndpoint &relay,
const std::wstring &relayClient,
- const std::optional<PingableHosts> &pingableHosts
+ const std::optional<PingableHosts> &pingableHosts,
+ const std::optional<WinFwEndpoint> &allowedEndpoint
)
{
Ruleset ruleset;
@@ -182,6 +214,11 @@ bool FwContext::applyPolicyConnecting
AppendSettingsRules(ruleset, settings);
AppendRelayRules(ruleset, relay, relayClient);
+ if (allowedEndpoint.has_value())
+ {
+ AppendAllowedEndpointRules(ruleset, allowedEndpoint.value());
+ }
+
//
// Permit pinging the gateway inside the tunnel.
//
@@ -208,7 +245,7 @@ bool FwContext::applyPolicyConnecting
bool FwContext::applyPolicyConnected
(
const WinFwSettings &settings,
- const WinFwRelay &relay,
+ const WinFwEndpoint &relay,
const std::wstring &relayClient,
const std::wstring &tunnelInterfaceAlias,
const std::vector<wfp::IpAddress> &tunnelDnsServers,
@@ -252,9 +289,9 @@ bool FwContext::applyPolicyConnected
return status;
}
-bool FwContext::applyPolicyBlocked(const WinFwSettings &settings)
+bool FwContext::applyPolicyBlocked(const WinFwSettings &settings, const std::optional<WinFwEndpoint> &allowedEndpoint)
{
- const auto status = applyRuleset(composePolicyBlocked(settings));
+ const auto status = applyRuleset(composePolicyBlocked(settings, allowedEndpoint));
if (status)
{
@@ -284,13 +321,18 @@ FwContext::Policy FwContext::activePolicy() const
return m_activePolicy;
}
-FwContext::Ruleset FwContext::composePolicyBlocked(const WinFwSettings &settings)
+FwContext::Ruleset FwContext::composePolicyBlocked(const WinFwSettings &settings, const std::optional<WinFwEndpoint> &allowedEndpoint)
{
Ruleset ruleset;
AppendNetBlockedRules(ruleset);
AppendSettingsRules(ruleset, settings);
+ if (allowedEndpoint.has_value())
+ {
+ AppendAllowedEndpointRules(ruleset, allowedEndpoint.value());
+ }
+
return ruleset;
}
@@ -302,7 +344,7 @@ bool FwContext::applyBaseConfiguration()
});
}
-bool FwContext::applyBlockedBaseConfiguration(const WinFwSettings &settings, uint32_t &checkpoint)
+bool FwContext::applyBlockedBaseConfiguration(const WinFwSettings &settings, const std::optional<WinFwEndpoint> &allowedEndpoint, uint32_t &checkpoint)
{
return m_sessionController->executeTransaction([&](SessionController &controller, wfp::FilterEngine &engine)
{
@@ -318,7 +360,7 @@ bool FwContext::applyBlockedBaseConfiguration(const WinFwSettings &settings, uin
//
checkpoint = controller.peekCheckpoint();
- return applyRulesetDirectly(composePolicyBlocked(settings), controller);
+ return applyRulesetDirectly(composePolicyBlocked(settings, allowedEndpoint), controller);
});
}
diff --git a/windows/winfw/src/winfw/fwcontext.h b/windows/winfw/src/winfw/fwcontext.h
index 100672073a..bbbb1de485 100644
--- a/windows/winfw/src/winfw/fwcontext.h
+++ b/windows/winfw/src/winfw/fwcontext.h
@@ -20,7 +20,8 @@ public:
FwContext
(
uint32_t timeout,
- const WinFwSettings &settings
+ const WinFwSettings &settings,
+ const std::optional<WinFwEndpoint> &allowedEndpoint
);
struct PingableHosts
@@ -32,22 +33,26 @@ public:
bool applyPolicyConnecting
(
const WinFwSettings &settings,
- const WinFwRelay &relay,
+ const WinFwEndpoint &relay,
const std::wstring &relayClient,
- const std::optional<PingableHosts> &pingableHosts
+ const std::optional<PingableHosts> &pingableHosts,
+ const std::optional<WinFwEndpoint> &allowedEndpoint
);
bool applyPolicyConnected
(
const WinFwSettings &settings,
- const WinFwRelay &relay,
+ const WinFwEndpoint &relay,
const std::wstring &relayClient,
const std::wstring &tunnelInterfaceAlias,
const std::vector<wfp::IpAddress> &tunnelDnsServers,
const std::vector<wfp::IpAddress> &nonTunnelDnsServers
);
- bool applyPolicyBlocked(const WinFwSettings &settings);
+ bool applyPolicyBlocked(
+ const WinFwSettings &settings,
+ const std::optional<WinFwEndpoint> &allowedEndpoint
+ );
bool reset();
@@ -68,10 +73,10 @@ private:
FwContext(const FwContext &) = delete;
FwContext &operator=(const FwContext &) = delete;
- Ruleset composePolicyBlocked(const WinFwSettings &settings);
+ Ruleset composePolicyBlocked(const WinFwSettings &settings, const std::optional<WinFwEndpoint> &allowedEndpoint);
bool applyBaseConfiguration();
- bool applyBlockedBaseConfiguration(const WinFwSettings &settings, uint32_t &checkpoint);
+ bool applyBlockedBaseConfiguration(const WinFwSettings &settings, const std::optional<WinFwEndpoint> &allowedEndpoint, uint32_t &checkpoint);
bool applyCommonBaseConfiguration(SessionController &controller, wfp::FilterEngine &engine);
bool applyRuleset(const Ruleset &ruleset);
diff --git a/windows/winfw/src/winfw/mullvadguids.cpp b/windows/winfw/src/winfw/mullvadguids.cpp
index 0a22be1740..417b157f82 100644
--- a/windows/winfw/src/winfw/mullvadguids.cpp
+++ b/windows/winfw/src/winfw/mullvadguids.cpp
@@ -129,6 +129,7 @@ MullvadGuids::DetailedIdentityRegistry MullvadGuids::DetailedRegistry(IdentityQu
registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitDhcpServer_Inbound_Request_Ipv4()));
registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitDhcpServer_Outbound_Response_Ipv4()));
registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitVpnRelay()));
+ registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitEndpoint()));
registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitVpnTunnel_Outbound_Ipv4()));
registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitVpnTunnel_Outbound_Ipv6()));
registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitVpnTunnelService_Ipv4()));
@@ -644,6 +645,20 @@ const GUID &MullvadGuids::Filter_Baseline_PermitVpnRelay()
}
//static
+const GUID &MullvadGuids::Filter_Baseline_PermitEndpoint()
+{
+ static const GUID g =
+ {
+ 0x99dc8dac,
+ 0x8520,
+ 0x41be,
+ { 0xbf, 0xab, 0x0c, 0x9, 0xbf, 0x12, 0xeb, 0 }
+ };
+
+ return g;
+}
+
+//static
const GUID &MullvadGuids::Filter_Baseline_PermitVpnTunnel_Outbound_Ipv4()
{
static const GUID g =
diff --git a/windows/winfw/src/winfw/mullvadguids.h b/windows/winfw/src/winfw/mullvadguids.h
index 11e396fc2b..7f00863811 100644
--- a/windows/winfw/src/winfw/mullvadguids.h
+++ b/windows/winfw/src/winfw/mullvadguids.h
@@ -69,6 +69,8 @@ public:
static const GUID &Filter_Baseline_PermitVpnRelay();
+ static const GUID &Filter_Baseline_PermitEndpoint();
+
static const GUID &Filter_Baseline_PermitVpnTunnel_Outbound_Ipv4();
static const GUID &Filter_Baseline_PermitVpnTunnel_Outbound_Ipv6();
diff --git a/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp b/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp
new file mode 100644
index 0000000000..217631579d
--- /dev/null
+++ b/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp
@@ -0,0 +1,87 @@
+#include "stdafx.h"
+#include "permitendpoint.h"
+#include <winfw/mullvadguids.h>
+#include <libwfp/filterbuilder.h>
+#include <libwfp/conditionbuilder.h>
+#include <libwfp/conditions/conditionprotocol.h>
+#include <libwfp/conditions/conditionip.h>
+#include <libwfp/conditions/conditionport.h>
+#include <libwfp/conditions/conditionapplication.h>
+#include <libcommon/error.h>
+
+using namespace wfp::conditions;
+
+namespace rules::baseline
+{
+
+namespace
+{
+
+const GUID &OutboundLayerFromIp(const wfp::IpAddress &ip)
+{
+ switch (ip.type())
+ {
+ case wfp::IpAddress::Type::Ipv4: return FWPM_LAYER_ALE_AUTH_CONNECT_V4;
+ case wfp::IpAddress::Type::Ipv6: return FWPM_LAYER_ALE_AUTH_CONNECT_V6;
+ default:
+ {
+ THROW_ERROR("Missing case handler in switch clause");
+ }
+ };
+}
+
+std::unique_ptr<ConditionProtocol> CreateProtocolCondition(PermitEndpoint::Protocol protocol)
+{
+ switch (protocol)
+ {
+ case PermitEndpoint::Protocol::Tcp: return ConditionProtocol::Tcp();
+ case PermitEndpoint::Protocol::Udp: return ConditionProtocol::Udp();
+ default:
+ {
+ THROW_ERROR("Missing case handler in switch clause");
+ }
+ };
+}
+
+} // anonymous namespace
+
+PermitEndpoint::PermitEndpoint
+(
+ const wfp::IpAddress &address,
+ uint16_t port,
+ Protocol protocol
+)
+ : m_address(address)
+ , m_port(port)
+ , m_protocol(protocol)
+{
+}
+
+bool PermitEndpoint::apply(IObjectInstaller &objectInstaller)
+{
+ wfp::FilterBuilder filterBuilder;
+
+ //
+ // Permit outbound connections to endpoint.
+ //
+
+ filterBuilder
+ .key(MullvadGuids::Filter_Baseline_PermitEndpoint())
+ .name(L"Permit outbound connections to a given endpoint")
+ .description(L"This filter is part of a rule that permits traffic to a specific endpoint")
+ .provider(MullvadGuids::Provider())
+ .layer(OutboundLayerFromIp(m_address))
+ .sublayer(MullvadGuids::SublayerBaseline())
+ .weight(wfp::FilterBuilder::WeightClass::Max)
+ .permit();
+
+ wfp::ConditionBuilder conditionBuilder(OutboundLayerFromIp(m_address));
+
+ conditionBuilder.add_condition(ConditionIp::Remote(m_address));
+ conditionBuilder.add_condition(ConditionPort::Remote(m_port));
+ conditionBuilder.add_condition(CreateProtocolCondition(m_protocol));
+
+ return objectInstaller.addFilter(filterBuilder, conditionBuilder);
+}
+
+}
diff --git a/windows/winfw/src/winfw/rules/baseline/permitendpoint.h b/windows/winfw/src/winfw/rules/baseline/permitendpoint.h
new file mode 100644
index 0000000000..cfa57b003d
--- /dev/null
+++ b/windows/winfw/src/winfw/rules/baseline/permitendpoint.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <winfw/rules/ifirewallrule.h>
+#include <libwfp/ipaddress.h>
+#include <string>
+
+namespace rules::baseline
+{
+
+class PermitEndpoint : public IFirewallRule
+{
+public:
+
+ enum class Protocol
+ {
+ Tcp,
+ Udp
+ };
+
+ PermitEndpoint
+ (
+ const wfp::IpAddress &address,
+ uint16_t port,
+ Protocol protocol
+ );
+
+ bool apply(IObjectInstaller &objectInstaller) override;
+
+private:
+
+ const wfp::IpAddress m_address;
+ const uint16_t m_port;
+ const Protocol m_protocol;
+};
+
+}
diff --git a/windows/winfw/src/winfw/winfw.cpp b/windows/winfw/src/winfw/winfw.cpp
index f2d5a66b2a..ee7842877e 100644
--- a/windows/winfw/src/winfw/winfw.cpp
+++ b/windows/winfw/src/winfw/winfw.cpp
@@ -65,6 +65,16 @@ HandlePolicyException(const common::error::WindowsException &err)
return WINFW_POLICY_STATUS_GENERAL_FAILURE;
}
+template<typename T>
+std::optional<T> MakeOptional(T* object)
+{
+ if (nullptr == object)
+ {
+ return std::nullopt;
+ }
+ return std::make_optional(*object);
+}
+
//
// Networks for which DNS requests can be made on all network adapters.
//
@@ -136,6 +146,7 @@ WINFW_API
WinFw_InitializeBlocked(
uint32_t timeout,
const WinFwSettings *settings,
+ const WinFwEndpoint *allowedEndpoint,
MullvadLogSink logSink,
void *logSinkContext
)
@@ -162,7 +173,7 @@ WinFw_InitializeBlocked(
g_logSink = logSink;
g_logSinkContext = logSinkContext;
- g_fwContext = new FwContext(timeout_ms, *settings);
+ g_fwContext = new FwContext(timeout_ms, *settings, MakeOptional(allowedEndpoint));
}
catch (std::exception &err)
{
@@ -247,9 +258,10 @@ WINFW_POLICY_STATUS
WINFW_API
WinFw_ApplyPolicyConnecting(
const WinFwSettings *settings,
- const WinFwRelay *relay,
+ const WinFwEndpoint *relay,
const wchar_t *relayClient,
- const PingableHosts *pingableHosts
+ const PingableHosts *pingableHosts,
+ const WinFwEndpoint *allowedEndpoint
)
{
if (nullptr == g_fwContext)
@@ -278,7 +290,8 @@ WinFw_ApplyPolicyConnecting(
*settings,
*relay,
relayClient,
- ConvertPingableHosts(pingableHosts)
+ ConvertPingableHosts(pingableHosts),
+ MakeOptional(allowedEndpoint)
) ? WINFW_POLICY_STATUS_SUCCESS : WINFW_POLICY_STATUS_GENERAL_FAILURE;
}
catch (common::error::WindowsException &err)
@@ -305,7 +318,7 @@ WINFW_POLICY_STATUS
WINFW_API
WinFw_ApplyPolicyConnected(
const WinFwSettings *settings,
- const WinFwRelay *relay,
+ const WinFwEndpoint *relay,
const wchar_t *relayClient,
const wchar_t *tunnelInterfaceAlias,
const wchar_t *v4Gateway,
@@ -447,7 +460,8 @@ WINFW_LINKAGE
WINFW_POLICY_STATUS
WINFW_API
WinFw_ApplyPolicyBlocked(
- const WinFwSettings *settings
+ const WinFwSettings *settings,
+ const WinFwEndpoint *allowedEndpoint
)
{
if (nullptr == g_fwContext)
@@ -462,7 +476,7 @@ WinFw_ApplyPolicyBlocked(
THROW_ERROR("Invalid argument: settings");
}
- return g_fwContext->applyPolicyBlocked(*settings)
+ return g_fwContext->applyPolicyBlocked(*settings, MakeOptional(allowedEndpoint))
? WINFW_POLICY_STATUS_SUCCESS
: WINFW_POLICY_STATUS_GENERAL_FAILURE;
}
diff --git a/windows/winfw/src/winfw/winfw.h b/windows/winfw/src/winfw/winfw.h
index f0a487cb12..23163786e9 100644
--- a/windows/winfw/src/winfw/winfw.h
+++ b/windows/winfw/src/winfw/winfw.h
@@ -37,13 +37,13 @@ enum WinFwProtocol : uint8_t
Udp = 1
};
-typedef struct tag_WinFwRelay
+typedef struct tag_WinFwEndpoint
{
const wchar_t *ip;
uint16_t port;
WinFwProtocol protocol;
}
-WinFwRelay;
+WinFwEndpoint;
#pragma pack(pop)
@@ -88,6 +88,7 @@ WINFW_API
WinFw_InitializeBlocked(
uint32_t timeout,
const WinFwSettings *settings,
+ const WinFwEndpoint *allowedEndpoint,
MullvadLogSink logSink,
void *logSinkContext
);
@@ -155,9 +156,10 @@ WINFW_POLICY_STATUS
WINFW_API
WinFw_ApplyPolicyConnecting(
const WinFwSettings *settings,
- const WinFwRelay *relay,
+ const WinFwEndpoint *relay,
const wchar_t *relayClient,
- const PingableHosts *pingableHosts
+ const PingableHosts *pingableHosts,
+ const WinFwEndpoint *allowedEndpoint
);
//
@@ -183,7 +185,7 @@ WINFW_POLICY_STATUS
WINFW_API
WinFw_ApplyPolicyConnected(
const WinFwSettings *settings,
- const WinFwRelay *relay,
+ const WinFwEndpoint *relay,
const wchar_t *relayClient,
const wchar_t *tunnelInterfaceAlias,
const wchar_t *v4Gateway,
@@ -203,7 +205,8 @@ WINFW_LINKAGE
WINFW_POLICY_STATUS
WINFW_API
WinFw_ApplyPolicyBlocked(
- const WinFwSettings *settings
+ const WinFwSettings *settings,
+ const WinFwEndpoint *allowedEndpoint
);
//
diff --git a/windows/winfw/src/winfw/winfw.vcxproj b/windows/winfw/src/winfw/winfw.vcxproj
index 8f9c37f919..3f9502a10d 100644
--- a/windows/winfw/src/winfw/winfw.vcxproj
+++ b/windows/winfw/src/winfw/winfw.vcxproj
@@ -27,6 +27,7 @@
<ClCompile Include="rules\baseline\permitdhcp.cpp" />
<ClCompile Include="rules\baseline\permitdhcpserver.cpp" />
<ClCompile Include="rules\baseline\permitdns.cpp" />
+ <ClCompile Include="rules\baseline\permitendpoint.cpp" />
<ClCompile Include="rules\baseline\permitlan.cpp" />
<ClCompile Include="rules\baseline\permitlanservice.cpp" />
<ClCompile Include="rules\baseline\permitloopback.cpp" />
@@ -61,6 +62,7 @@
<ClInclude Include="rules\baseline\permitdhcp.h" />
<ClInclude Include="rules\baseline\permitdhcpserver.h" />
<ClInclude Include="rules\baseline\permitdns.h" />
+ <ClInclude Include="rules\baseline\permitendpoint.h" />
<ClInclude Include="rules\baseline\permitlan.h" />
<ClInclude Include="rules\baseline\permitlanservice.h" />
<ClInclude Include="rules\baseline\permitloopback.h" />
diff --git a/windows/winfw/src/winfw/winfw.vcxproj.filters b/windows/winfw/src/winfw/winfw.vcxproj.filters
index 312045876e..7a2aa85487 100644
--- a/windows/winfw/src/winfw/winfw.vcxproj.filters
+++ b/windows/winfw/src/winfw/winfw.vcxproj.filters
@@ -61,6 +61,9 @@
<ClCompile Include="rules\persistent\blockall.cpp">
<Filter>rules\persistent</Filter>
</ClCompile>
+ <ClCompile Include="rules\baseline\permitendpoint.cpp">
+ <Filter>rules\baseline</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
@@ -132,6 +135,9 @@
<ClInclude Include="rules\persistent\blockall.h">
<Filter>rules\persistent</Filter>
</ClInclude>
+ <ClInclude Include="rules\baseline\permitendpoint.h">
+ <Filter>rules\baseline</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="rules">