diff options
Diffstat (limited to 'windows')
| -rw-r--r-- | windows/winfw/src/winfw/fwcontext.cpp | 49 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/fwcontext.h | 3 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp | 14 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/rules/baseline/permitvpntunnel.cpp | 46 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/rules/baseline/permitvpntunnel.h | 15 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/rules/baseline/permitvpntunnelservice.cpp | 64 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/rules/baseline/permitvpntunnelservice.h | 10 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/rules/multi/permitvpnrelay.cpp | 14 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/rules/shared.cpp | 34 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/rules/shared.h | 7 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/winfw.cpp | 11 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/winfw.h | 23 |
12 files changed, 230 insertions, 60 deletions
diff --git a/windows/winfw/src/winfw/fwcontext.cpp b/windows/winfw/src/winfw/fwcontext.cpp index fe6c227e7f..b72cefe2d3 100644 --- a/windows/winfw/src/winfw/fwcontext.cpp +++ b/windows/winfw/src/winfw/fwcontext.cpp @@ -185,7 +185,8 @@ bool FwContext::applyPolicyConnecting const WinFwEndpoint &relay, const std::wstring &relayClient, const std::optional<std::wstring> &tunnelInterfaceAlias, - const std::optional<WinFwAllowedEndpoint> &allowedEndpoint + const std::optional<WinFwAllowedEndpoint> &allowedEndpoint, + const WinFwAllowedTunnelTraffic &allowedTunnelTraffic ) { Ruleset ruleset; @@ -201,13 +202,39 @@ bool FwContext::applyPolicyConnecting if (tunnelInterfaceAlias.has_value()) { - ruleset.emplace_back(std::make_unique<baseline::PermitVpnTunnel>( - *tunnelInterfaceAlias - )); - - ruleset.emplace_back(std::make_unique<baseline::PermitVpnTunnelService>( - *tunnelInterfaceAlias - )); + switch (allowedTunnelTraffic.type) + { + case WinFwAllowedTunnelTrafficType::All: + { + ruleset.emplace_back(std::make_unique<baseline::PermitVpnTunnel>( + *tunnelInterfaceAlias, + std::nullopt + )); + ruleset.emplace_back(std::make_unique<baseline::PermitVpnTunnelService>( + *tunnelInterfaceAlias, + std::nullopt + )); + break; + } + case WinFwAllowedTunnelTrafficType::Only: + { + const auto onlyEndpoint = std::make_optional(baseline::PermitVpnTunnel::Endpoint{ + wfp::IpAddress(allowedTunnelTraffic.endpoint->ip), + allowedTunnelTraffic.endpoint->port, + allowedTunnelTraffic.endpoint->protocol + }); + ruleset.emplace_back(std::make_unique<baseline::PermitVpnTunnel>( + *tunnelInterfaceAlias, + onlyEndpoint + )); + ruleset.emplace_back(std::make_unique<baseline::PermitVpnTunnelService>( + *tunnelInterfaceAlias, + onlyEndpoint + )); + break; + } + // For the "None" case, do nothing. + } } const auto status = applyRuleset(ruleset); @@ -250,11 +277,13 @@ bool FwContext::applyPolicyConnected } ruleset.emplace_back(std::make_unique<baseline::PermitVpnTunnel>( - tunnelInterfaceAlias + tunnelInterfaceAlias, + std::nullopt )); ruleset.emplace_back(std::make_unique<baseline::PermitVpnTunnelService>( - tunnelInterfaceAlias + tunnelInterfaceAlias, + std::nullopt )); const auto status = applyRuleset(ruleset); diff --git a/windows/winfw/src/winfw/fwcontext.h b/windows/winfw/src/winfw/fwcontext.h index bf67565993..5fc23f09a7 100644 --- a/windows/winfw/src/winfw/fwcontext.h +++ b/windows/winfw/src/winfw/fwcontext.h @@ -30,7 +30,8 @@ public: const WinFwEndpoint &relay, const std::wstring &relayClient, const std::optional<std::wstring> &tunnelInterfaceAlias, - const std::optional<WinFwAllowedEndpoint> &allowedEndpoint + const std::optional<WinFwAllowedEndpoint> &allowedEndpoint, + const WinFwAllowedTunnelTraffic &allowedTunnelTraffic ); bool applyPolicyConnected diff --git a/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp b/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp index 09d8937535..c1c74ba6ba 100644 --- a/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp +++ b/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "permitendpoint.h" #include <winfw/mullvadguids.h> +#include <winfw/rules/shared.h> #include <libwfp/filterbuilder.h> #include <libwfp/conditionbuilder.h> #include <libwfp/conditions/conditionprotocol.h> @@ -30,19 +31,6 @@ const GUID &OutboundLayerFromIp(const wfp::IpAddress &ip) }; } -std::unique_ptr<ConditionProtocol> CreateProtocolCondition(WinFwProtocol protocol) -{ - switch (protocol) - { - case WinFwProtocol::Tcp: return ConditionProtocol::Tcp(); - case WinFwProtocol::Udp: return ConditionProtocol::Udp(); - default: - { - THROW_ERROR("Missing case handler in switch clause"); - } - }; -} - } // anonymous namespace PermitEndpoint::PermitEndpoint diff --git a/windows/winfw/src/winfw/rules/baseline/permitvpntunnel.cpp b/windows/winfw/src/winfw/rules/baseline/permitvpntunnel.cpp index e756d68464..d9a1af0f28 100644 --- a/windows/winfw/src/winfw/rules/baseline/permitvpntunnel.cpp +++ b/windows/winfw/src/winfw/rules/baseline/permitvpntunnel.cpp @@ -1,17 +1,26 @@ #include "stdafx.h" #include "permitvpntunnel.h" #include <winfw/mullvadguids.h> +#include <winfw/rules/shared.h> #include <libwfp/filterbuilder.h> #include <libwfp/conditionbuilder.h> #include <libwfp/conditions/conditioninterface.h> +#include <libwfp/conditions/conditionip.h> +#include <libwfp/conditions/conditionport.h> +#include <libwfp/conditions/conditionprotocol.h> +#include <libcommon/error.h> using namespace wfp::conditions; namespace rules::baseline { -PermitVpnTunnel::PermitVpnTunnel(const std::wstring &tunnelInterfaceAlias) +PermitVpnTunnel::PermitVpnTunnel( + const std::wstring &tunnelInterfaceAlias, + const std::optional<Endpoint> &onlyEndpoint +) : m_tunnelInterfaceAlias(tunnelInterfaceAlias) + , m_tunnelOnlyEndpoint(onlyEndpoint) { } @@ -19,6 +28,9 @@ bool PermitVpnTunnel::apply(IObjectInstaller &objectInstaller) { wfp::FilterBuilder filterBuilder; + bool includeV4 = !m_tunnelOnlyEndpoint.has_value() || m_tunnelOnlyEndpoint->ip.type() == wfp::IpAddress::Ipv4; + bool includeV6 = !m_tunnelOnlyEndpoint.has_value() || m_tunnelOnlyEndpoint->ip.type() == wfp::IpAddress::Ipv6; + // // #1 Permit outbound connections, IPv4. // @@ -33,11 +45,22 @@ bool PermitVpnTunnel::apply(IObjectInstaller &objectInstaller) .weight(wfp::FilterBuilder::WeightClass::Medium) .permit(); + if (includeV4) { wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_CONNECT_V4); conditionBuilder.add_condition(ConditionInterface::Alias(m_tunnelInterfaceAlias)); + if (m_tunnelOnlyEndpoint.has_value()) + { + conditionBuilder.add_condition(ConditionIp::Remote(m_tunnelOnlyEndpoint->ip)); + if (ProtocolHasPort(m_tunnelOnlyEndpoint->protocol)) + { + conditionBuilder.add_condition(ConditionPort::Remote(m_tunnelOnlyEndpoint->port)); + } + conditionBuilder.add_condition(CreateProtocolCondition(m_tunnelOnlyEndpoint->protocol)); + } + if (!objectInstaller.addFilter(filterBuilder, conditionBuilder)) { return false; @@ -53,11 +76,26 @@ bool PermitVpnTunnel::apply(IObjectInstaller &objectInstaller) .name(L"Permit outbound connections on tunnel interface (IPv6)") .layer(FWPM_LAYER_ALE_AUTH_CONNECT_V6); - wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_CONNECT_V6); + if (includeV6) + { + wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_CONNECT_V6); - conditionBuilder.add_condition(ConditionInterface::Alias(m_tunnelInterfaceAlias)); + conditionBuilder.add_condition(ConditionInterface::Alias(m_tunnelInterfaceAlias)); + + if (m_tunnelOnlyEndpoint.has_value()) + { + conditionBuilder.add_condition(ConditionIp::Remote(m_tunnelOnlyEndpoint->ip)); + if (ProtocolHasPort(m_tunnelOnlyEndpoint->protocol)) + { + conditionBuilder.add_condition(ConditionPort::Remote(m_tunnelOnlyEndpoint->port)); + } + conditionBuilder.add_condition(CreateProtocolCondition(m_tunnelOnlyEndpoint->protocol)); + } + + return objectInstaller.addFilter(filterBuilder, conditionBuilder); + } - return objectInstaller.addFilter(filterBuilder, conditionBuilder); + return true; } } diff --git a/windows/winfw/src/winfw/rules/baseline/permitvpntunnel.h b/windows/winfw/src/winfw/rules/baseline/permitvpntunnel.h index 9c9a7b14c1..ee030a9f43 100644 --- a/windows/winfw/src/winfw/rules/baseline/permitvpntunnel.h +++ b/windows/winfw/src/winfw/rules/baseline/permitvpntunnel.h @@ -1,7 +1,10 @@ #pragma once #include <winfw/rules/ifirewallrule.h> +#include <winfw/winfw.h> +#include <libwfp/ipaddress.h> #include <string> +#include <optional> namespace rules::baseline { @@ -10,13 +13,23 @@ class PermitVpnTunnel : public IFirewallRule { public: - PermitVpnTunnel(const std::wstring &tunnelInterfaceAlias); + struct Endpoint { + wfp::IpAddress ip; + uint16_t port; + WinFwProtocol protocol; + }; + + PermitVpnTunnel( + const std::wstring &tunnelInterfaceAlias, + const std::optional<Endpoint> &onlyEndpoint + ); bool apply(IObjectInstaller &objectInstaller) override; private: const std::wstring m_tunnelInterfaceAlias; + const std::optional<Endpoint> m_tunnelOnlyEndpoint; }; } diff --git a/windows/winfw/src/winfw/rules/baseline/permitvpntunnelservice.cpp b/windows/winfw/src/winfw/rules/baseline/permitvpntunnelservice.cpp index 00fbc8e76b..42214b6a77 100644 --- a/windows/winfw/src/winfw/rules/baseline/permitvpntunnelservice.cpp +++ b/windows/winfw/src/winfw/rules/baseline/permitvpntunnelservice.cpp @@ -1,17 +1,26 @@ #include "stdafx.h" #include "permitvpntunnelservice.h" #include <winfw/mullvadguids.h> +#include <winfw/rules/shared.h> #include <libwfp/filterbuilder.h> #include <libwfp/conditionbuilder.h> #include <libwfp/conditions/conditioninterface.h> +#include <libwfp/conditions/conditionip.h> +#include <libwfp/conditions/conditionport.h> +#include <libwfp/conditions/conditionprotocol.h> +#include <libcommon/error.h> using namespace wfp::conditions; namespace rules::baseline { -PermitVpnTunnelService::PermitVpnTunnelService(const std::wstring &tunnelInterfaceAlias) +PermitVpnTunnelService::PermitVpnTunnelService( + const std::wstring &tunnelInterfaceAlias, + const std::optional<PermitVpnTunnel::Endpoint> &onlyEndpoint +) : m_tunnelInterfaceAlias(tunnelInterfaceAlias) + , m_tunnelOnlyEndpoint(onlyEndpoint) { } @@ -19,6 +28,9 @@ bool PermitVpnTunnelService::apply(IObjectInstaller &objectInstaller) { wfp::FilterBuilder filterBuilder; + bool includeV4 = !m_tunnelOnlyEndpoint.has_value() || m_tunnelOnlyEndpoint->ip.type() == wfp::IpAddress::Ipv4; + bool includeV6 = !m_tunnelOnlyEndpoint.has_value() || m_tunnelOnlyEndpoint->ip.type() == wfp::IpAddress::Ipv6; + // // #1 Permit inbound connections, IPv4. // @@ -35,26 +47,54 @@ bool PermitVpnTunnelService::apply(IObjectInstaller &objectInstaller) wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4); - conditionBuilder.add_condition(ConditionInterface::Alias(m_tunnelInterfaceAlias)); - - if (!objectInstaller.addFilter(filterBuilder, conditionBuilder)) + if (includeV4) { - return false; + conditionBuilder.add_condition(ConditionInterface::Alias(m_tunnelInterfaceAlias)); + + if (m_tunnelOnlyEndpoint.has_value()) + { + conditionBuilder.add_condition(ConditionIp::Remote(m_tunnelOnlyEndpoint->ip)); + if (ProtocolHasPort(m_tunnelOnlyEndpoint->protocol)) + { + conditionBuilder.add_condition(ConditionPort::Remote(m_tunnelOnlyEndpoint->port)); + } + conditionBuilder.add_condition(CreateProtocolCondition(m_tunnelOnlyEndpoint->protocol)); + } + + if (!objectInstaller.addFilter(filterBuilder, conditionBuilder)) + { + return false; + } } // // #2 Permit inbound connections, IPv6. // - filterBuilder - .key(MullvadGuids::Filter_Baseline_PermitVpnTunnelService_Ipv6()) - .name(L"Permit inbound connections on tunnel interface (IPv6)") - .layer(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6); + if (includeV6) + { + filterBuilder + .key(MullvadGuids::Filter_Baseline_PermitVpnTunnelService_Ipv6()) + .name(L"Permit inbound connections on tunnel interface (IPv6)") + .layer(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6); + + conditionBuilder.reset(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6); + conditionBuilder.add_condition(ConditionInterface::Alias(m_tunnelInterfaceAlias)); - conditionBuilder.reset(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6); - conditionBuilder.add_condition(ConditionInterface::Alias(m_tunnelInterfaceAlias)); + if (m_tunnelOnlyEndpoint.has_value()) + { + conditionBuilder.add_condition(ConditionIp::Remote(m_tunnelOnlyEndpoint->ip)); + if (ProtocolHasPort(m_tunnelOnlyEndpoint->protocol)) + { + conditionBuilder.add_condition(ConditionPort::Remote(m_tunnelOnlyEndpoint->port)); + } + conditionBuilder.add_condition(CreateProtocolCondition(m_tunnelOnlyEndpoint->protocol)); + } + + return objectInstaller.addFilter(filterBuilder, conditionBuilder); + } - return objectInstaller.addFilter(filterBuilder, conditionBuilder); + return true; } } diff --git a/windows/winfw/src/winfw/rules/baseline/permitvpntunnelservice.h b/windows/winfw/src/winfw/rules/baseline/permitvpntunnelservice.h index 8880c06328..8011659b97 100644 --- a/windows/winfw/src/winfw/rules/baseline/permitvpntunnelservice.h +++ b/windows/winfw/src/winfw/rules/baseline/permitvpntunnelservice.h @@ -1,7 +1,11 @@ #pragma once #include <winfw/rules/ifirewallrule.h> +#include <winfw/rules/baseline/permitvpntunnel.h> +#include <winfw/winfw.h> +#include <libwfp/ipaddress.h> #include <string> +#include <optional> namespace rules::baseline { @@ -10,13 +14,17 @@ class PermitVpnTunnelService : public IFirewallRule { public: - PermitVpnTunnelService(const std::wstring &tunnelInterfaceAlias); + PermitVpnTunnelService( + const std::wstring &tunnelInterfaceAlias, + const std::optional<PermitVpnTunnel::Endpoint> &onlyEndpoint + ); bool apply(IObjectInstaller &objectInstaller) override; private: const std::wstring m_tunnelInterfaceAlias; + const std::optional<PermitVpnTunnel::Endpoint> m_tunnelOnlyEndpoint; }; } diff --git a/windows/winfw/src/winfw/rules/multi/permitvpnrelay.cpp b/windows/winfw/src/winfw/rules/multi/permitvpnrelay.cpp index a403230df9..3c913cab14 100644 --- a/windows/winfw/src/winfw/rules/multi/permitvpnrelay.cpp +++ b/windows/winfw/src/winfw/rules/multi/permitvpnrelay.cpp @@ -2,6 +2,7 @@ #include "permitvpnrelay.h" #include <winfw/mullvadguids.h> #include <winfw/winfw.h> +#include <winfw/rules/shared.h> #include <libwfp/filterbuilder.h> #include <libwfp/conditionbuilder.h> #include <libwfp/conditions/conditionprotocol.h> @@ -31,19 +32,6 @@ const GUID &LayerFromIp(const wfp::IpAddress &ip) }; } -std::unique_ptr<ConditionProtocol> CreateProtocolCondition(WinFwProtocol protocol) -{ - switch (protocol) - { - case WinFwProtocol::Tcp: return ConditionProtocol::Tcp(); - case WinFwProtocol::Udp: return ConditionProtocol::Udp(); - default: - { - THROW_ERROR("Missing case handler in switch clause"); - } - }; -} - const GUID &TranslateSublayer(PermitVpnRelay::Sublayer sublayer) { switch (sublayer) diff --git a/windows/winfw/src/winfw/rules/shared.cpp b/windows/winfw/src/winfw/rules/shared.cpp index 66cbbdfc83..1d1123e3eb 100644 --- a/windows/winfw/src/winfw/rules/shared.cpp +++ b/windows/winfw/src/winfw/rules/shared.cpp @@ -2,6 +2,8 @@ #include "shared.h" #include <libcommon/error.h> +using namespace wfp::conditions; + namespace rules { @@ -37,4 +39,36 @@ void SplitAddresses(const IpSet &in, IpSet &outIpv4, IpSet &outIpv6) } } +std::unique_ptr<wfp::conditions::ConditionProtocol> CreateProtocolCondition(WinFwProtocol protocol) +{ + switch (protocol) + { + case WinFwProtocol::Tcp: return ConditionProtocol::Tcp(); + case WinFwProtocol::Udp: return ConditionProtocol::Udp(); + case WinFwProtocol::Icmp: return ConditionProtocol::Icmp(); + case WinFwProtocol::IcmpV6: return ConditionProtocol::IcmpV6(); + default: + { + THROW_ERROR("Missing case handler in switch clause"); + } + }; +} + +bool ProtocolHasPort(WinFwProtocol protocol) +{ + switch (protocol) + { + case WinFwProtocol::Tcp: + case WinFwProtocol::Udp: + return true; + case WinFwProtocol::Icmp: + case WinFwProtocol::IcmpV6: + return false; + default: + { + THROW_ERROR("Missing case handler in switch clause"); + } + }; +} + } diff --git a/windows/winfw/src/winfw/rules/shared.h b/windows/winfw/src/winfw/rules/shared.h index 1b08d3ed02..4f4da187ca 100644 --- a/windows/winfw/src/winfw/rules/shared.h +++ b/windows/winfw/src/winfw/rules/shared.h @@ -1,6 +1,9 @@ #pragma once #include <vector> +#include <memory> +#include <winfw/winfw.h> +#include <libwfp/conditions/conditionprotocol.h> #include <libwfp/ipaddress.h> namespace rules @@ -10,4 +13,8 @@ using IpSet = std::vector<wfp::IpAddress>; void SplitAddresses(const IpSet &in, IpSet &outIpv4, IpSet &outIpv6); +std::unique_ptr<wfp::conditions::ConditionProtocol> CreateProtocolCondition(WinFwProtocol protocol); + +bool ProtocolHasPort(WinFwProtocol protocol); + } diff --git a/windows/winfw/src/winfw/winfw.cpp b/windows/winfw/src/winfw/winfw.cpp index ae0f0791de..4110dcd2f8 100644 --- a/windows/winfw/src/winfw/winfw.cpp +++ b/windows/winfw/src/winfw/winfw.cpp @@ -233,7 +233,8 @@ WinFw_ApplyPolicyConnecting( const WinFwEndpoint *relay, const wchar_t *relayClient, const wchar_t *tunnelInterfaceAlias, - const WinFwAllowedEndpoint *allowedEndpoint + const WinFwAllowedEndpoint *allowedEndpoint, + const WinFwAllowedTunnelTraffic *allowedTunnelTraffic ) { if (nullptr == g_fwContext) @@ -258,12 +259,18 @@ WinFw_ApplyPolicyConnecting( THROW_ERROR("Invalid argument: relayClient"); } + if (nullptr == allowedTunnelTraffic) + { + THROW_ERROR("Invalid argument: allowedTunnelTraffic"); + } + return g_fwContext->applyPolicyConnecting( *settings, *relay, relayClient, tunnelInterfaceAlias != nullptr ? std::make_optional(tunnelInterfaceAlias) : std::nullopt, - MakeOptional(allowedEndpoint) + MakeOptional(allowedEndpoint), + *allowedTunnelTraffic ) ? WINFW_POLICY_STATUS_SUCCESS : WINFW_POLICY_STATUS_GENERAL_FAILURE; } catch (common::error::WindowsException &err) diff --git a/windows/winfw/src/winfw/winfw.h b/windows/winfw/src/winfw/winfw.h index 4913ae7baf..6394893d91 100644 --- a/windows/winfw/src/winfw/winfw.h +++ b/windows/winfw/src/winfw/winfw.h @@ -32,7 +32,9 @@ WinFwSettings; enum WinFwProtocol : uint8_t { Tcp = 0, - Udp = 1 + Udp = 1, + Icmp = 2, + IcmpV6 = 3 }; typedef struct tag_WinFwEndpoint @@ -55,6 +57,20 @@ typedef struct tag_WinFwAllowedEndpoint } WinFwAllowedEndpoint; +enum WinFwAllowedTunnelTrafficType : uint8_t +{ + None, + All, + Only +}; + +typedef struct tag_WinFwAllowedTunnelTraffic +{ + WinFwAllowedTunnelTrafficType type; + WinFwEndpoint *endpoint; +} +WinFwAllowedTunnelTraffic; + /////////////////////////////////////////////////////////////////////////////// // Functions /////////////////////////////////////////////////////////////////////////////// @@ -139,7 +155,7 @@ enum WINFW_POLICY_STATUS // Apply restrictions in the firewall that block all traffic, except: // - What is specified by settings // - Communication with the relay server -// - Non-DNS traffic inside the VPN tunnel +// - Specified in-tunnel traffic, except DNS. // extern "C" WINFW_LINKAGE @@ -150,7 +166,8 @@ WinFw_ApplyPolicyConnecting( const WinFwEndpoint *relay, const wchar_t *relayClient, const wchar_t *tunnelInterfaceAlias, - const WinFwAllowedEndpoint *allowedEndpoint + const WinFwAllowedEndpoint *allowedEndpoint, + const WinFwAllowedTunnelTraffic *allowedTunnelTraffic ); // |
