summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOdd Stranne <odd@mullvad.net>2020-06-09 12:13:16 +0200
committerOdd Stranne <odd@mullvad.net>2020-06-09 12:13:16 +0200
commitfbbc4096f7c5efcc4c7343f55f8b07eddaec1938 (patch)
treeb01d747127fee3ad5e6082c9566dc68e12e2f1cc
parent3a35547e4c4a00755b14d05f67ae5e636138f81b (diff)
parent1c39069982c78cda590678a6b02e2a9e94006b92 (diff)
downloadmullvadvpn-fbbc4096f7c5efcc4c7343f55f8b07eddaec1938.tar.xz
mullvadvpn-fbbc4096f7c5efcc4c7343f55f8b07eddaec1938.zip
Merge branch 'win-fw-restrict-relay-access'
-rw-r--r--mullvad-daemon/src/lib.rs11
-rw-r--r--mullvad-setup/src/main.rs2
-rw-r--r--talpid-core/src/firewall/mod.rs5
-rw-r--r--talpid-core/src/firewall/windows.rs39
-rw-r--r--talpid-core/src/tunnel_state_machine/mod.rs11
-rw-r--r--windows/winfw/src/winfw/fwcontext.cpp117
-rw-r--r--windows/winfw/src/winfw/fwcontext.h11
-rw-r--r--windows/winfw/src/winfw/rules/baseline/permitvpnrelay.h30
-rw-r--r--windows/winfw/src/winfw/rules/dns/permitnontunnel.h11
-rw-r--r--windows/winfw/src/winfw/rules/multi/permitvpnrelay.cpp (renamed from windows/winfw/src/winfw/rules/baseline/permitvpnrelay.cpp)38
-rw-r--r--windows/winfw/src/winfw/rules/multi/permitvpnrelay.h47
-rw-r--r--windows/winfw/src/winfw/winfw.cpp29
-rw-r--r--windows/winfw/src/winfw/winfw.h13
-rw-r--r--windows/winfw/src/winfw/winfw.vcxproj4
-rw-r--r--windows/winfw/src/winfw/winfw.vcxproj.filters15
15 files changed, 276 insertions, 107 deletions
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index f4cf17a839..9b1854d4a3 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -564,6 +564,8 @@ where
tunnel_state_machine_shutdown_tx,
#[cfg(target_os = "android")]
android_context,
+ #[cfg(windows)]
+ Self::get_approved_applications(),
)
.map_err(Error::TunnelError)?;
@@ -634,6 +636,15 @@ where
Ok(daemon)
}
+ #[cfg(windows)]
+ fn get_approved_applications() -> Vec<PathBuf> {
+ let resource_dir = mullvad_paths::get_resource_dir();
+ vec![
+ resource_dir.join("mullvad-daemon.exe"),
+ resource_dir.join("openvpn.exe"),
+ resource_dir.join("sslocal.exe"),
+ ]
+ }
/// Consume the `Daemon` and run the main event loop. Blocks until an error happens or a
/// shutdown event is received.
diff --git a/mullvad-setup/src/main.rs b/mullvad-setup/src/main.rs
index f8fda169b5..a01f832c3e 100644
--- a/mullvad-setup/src/main.rs
+++ b/mullvad-setup/src/main.rs
@@ -69,6 +69,8 @@ fn reset_firewall() -> Result<(), Error> {
let mut firewall = Firewall::new(FirewallArguments {
initialize_blocked: false,
allow_lan: None,
+ #[cfg(windows)]
+ approved_applications: vec!["foobar".into()],
})
.map_err(Error::FirewallError)?;
diff --git a/talpid-core/src/firewall/mod.rs b/talpid-core/src/firewall/mod.rs
index 110b0bb2a1..80c9b65713 100644
--- a/talpid-core/src/firewall/mod.rs
+++ b/talpid-core/src/firewall/mod.rs
@@ -7,6 +7,8 @@ use std::fmt;
use std::net::IpAddr;
#[cfg(unix)]
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+#[cfg(windows)]
+use std::path::PathBuf;
use talpid_types::net::Endpoint;
@@ -169,6 +171,9 @@ pub struct FirewallArguments {
pub initialize_blocked: bool,
/// This argument is required for the blocked state to configure the firewall correctly.
pub allow_lan: Option<bool>,
+ /// List of applications that are approved for communicating with the relay.
+ #[cfg(windows)]
+ pub approved_applications: Vec<PathBuf>,
}
impl Firewall {
diff --git a/talpid-core/src/firewall/windows.rs b/talpid-core/src/firewall/windows.rs
index 807bcd1167..d3b18c2c3a 100644
--- a/talpid-core/src/firewall/windows.rs
+++ b/talpid-core/src/firewall/windows.rs
@@ -52,12 +52,29 @@ impl FirewallT for Firewall {
fn new(args: FirewallArguments) -> Result<Self, Self::Error> {
let logging_context = b"WinFw\0".as_ptr();
+
+ let app_strings = args
+ .approved_applications
+ .iter()
+ .map(|app| Self::to_widestring(app.to_string_lossy()))
+ .collect::<Vec<_>>();
+ let app_ptrs = app_strings
+ .iter()
+ .map(|app| app.as_ptr())
+ .collect::<Vec<_>>();
+
+ let approved_applications = WinFwApprovedApplications {
+ apps: app_ptrs.as_ptr(),
+ num_apps: app_ptrs.len(),
+ };
+
if args.initialize_blocked {
let cfg = &WinFwSettings::new(args.allow_lan.unwrap());
unsafe {
WinFw_InitializeBlocked(
WINFW_TIMEOUT_SECONDS,
&cfg,
+ &approved_applications,
Some(log_sink),
logging_context,
)
@@ -65,8 +82,13 @@ impl FirewallT for Firewall {
};
} else {
unsafe {
- WinFw_Initialize(WINFW_TIMEOUT_SECONDS, Some(log_sink), logging_context)
- .into_result()?
+ WinFw_Initialize(
+ WINFW_TIMEOUT_SECONDS,
+ &approved_applications,
+ Some(log_sink),
+ logging_context,
+ )
+ .into_result()?
};
}
@@ -175,6 +197,11 @@ impl Firewall {
WideCString::new(buf).unwrap()
}
+ fn to_widestring<T: AsRef<str>>(string: T) -> WideCString {
+ let buf = string.as_ref().encode_utf16().collect::<Vec<_>>();
+ WideCString::new(buf).unwrap()
+ }
+
fn set_connected_state(
&mut self,
endpoint: &Endpoint,
@@ -284,6 +311,12 @@ mod winfw {
pub num_addresses: usize,
}
+ #[repr(C)]
+ pub struct WinFwApprovedApplications {
+ pub apps: *const *const libc::wchar_t,
+ pub num_apps: usize,
+ }
+
#[allow(dead_code)]
#[repr(u8)]
#[derive(Clone, Copy)]
@@ -303,6 +336,7 @@ mod winfw {
#[link_name = "WinFw_Initialize"]
pub fn WinFw_Initialize(
timeout: libc::c_uint,
+ approved_applications: *const WinFwApprovedApplications,
sink: Option<LogSink>,
sink_context: *const u8,
) -> InitializationResult;
@@ -311,6 +345,7 @@ mod winfw {
pub fn WinFw_InitializeBlocked(
timeout: libc::c_uint,
settings: &WinFwSettings,
+ approved_applications: *const WinFwApprovedApplications,
sink: Option<LogSink>,
sink_context: *const u8,
) -> InitializationResult;
diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs
index b0222ade67..7f867fdcd0 100644
--- a/talpid-core/src/tunnel_state_machine/mod.rs
+++ b/talpid-core/src/tunnel_state_machine/mod.rs
@@ -87,6 +87,7 @@ pub fn spawn(
state_change_listener: impl Sender<TunnelStateTransition> + Send + 'static,
shutdown_tx: oneshot::Sender<()>,
#[cfg(target_os = "android")] android_context: AndroidContext,
+ #[cfg(windows)] approved_applications: Vec<PathBuf>,
) -> Result<Arc<mpsc::UnboundedSender<TunnelCommand>>, Error> {
let (command_tx, command_rx) = mpsc::unbounded();
let command_tx = Arc::new(command_tx);
@@ -119,6 +120,8 @@ pub fn spawn(
command_rx,
state_change_listener,
shutdown_tx,
+ #[cfg(target_os = "windows")]
+ approved_applications,
) {
Ok((mut reactor, event_loop)) => {
startup_result_tx.send(Ok(())).expect(
@@ -159,6 +162,7 @@ fn create_event_loop(
commands: mpsc::UnboundedReceiver<TunnelCommand>,
state_change_listener: impl Sender<TunnelStateTransition>,
shutdown_tx: oneshot::Sender<()>,
+ #[cfg(windows)] approved_applications: Vec<PathBuf>,
) -> Result<(Core, impl Future<Item = (), Error = Error>), Error> {
let reactor = Core::new().map_err(Error::ReactorError)?;
let state_machine = TunnelStateMachine::new(
@@ -171,6 +175,8 @@ fn create_event_loop(
resource_dir,
cache_dir,
commands,
+ #[cfg(windows)]
+ approved_applications,
)?;
let future = state_machine
@@ -228,16 +234,21 @@ impl TunnelStateMachine {
resource_dir: PathBuf,
cache_dir: impl AsRef<Path>,
commands: mpsc::UnboundedReceiver<TunnelCommand>,
+ #[cfg(windows)] approved_applications: Vec<PathBuf>,
) -> Result<Self, Error> {
let args = if block_when_disconnected {
FirewallArguments {
initialize_blocked: true,
allow_lan: Some(allow_lan),
+ #[cfg(windows)]
+ approved_applications,
}
} else {
FirewallArguments {
initialize_blocked: false,
allow_lan: None,
+ #[cfg(windows)]
+ approved_applications,
}
};
diff --git a/windows/winfw/src/winfw/fwcontext.cpp b/windows/winfw/src/winfw/fwcontext.cpp
index 4883e6f6d8..7661fe95d4 100644
--- a/windows/winfw/src/winfw/fwcontext.cpp
+++ b/windows/winfw/src/winfw/fwcontext.cpp
@@ -11,14 +11,13 @@
#include "rules/baseline/permitlan.h"
#include "rules/baseline/permitlanservice.h"
#include "rules/baseline/permitloopback.h"
-#include "rules/baseline/permitvpnrelay.h"
#include "rules/baseline/permitvpntunnel.h"
#include "rules/baseline/permitvpntunnelservice.h"
#include "rules/baseline/permitping.h"
#include "rules/baseline/permitdns.h"
#include "rules/dns/blockall.h"
-#include "rules/dns/permitnontunnel.h"
#include "rules/dns/permittunnel.h"
+#include "rules/multi/permitvpnrelay.h"
#include <libwfp/transaction.h>
#include <libwfp/filterengine.h>
#include <libcommon/error.h>
@@ -30,12 +29,12 @@ using namespace rules;
namespace
{
-baseline::PermitVpnRelay::Protocol TranslateProtocol(WinFwProtocol protocol)
+multi::PermitVpnRelay::Protocol TranslateProtocol(WinFwProtocol protocol)
{
switch (protocol)
{
- case Tcp: return baseline::PermitVpnRelay::Protocol::Tcp;
- case Udp: return baseline::PermitVpnRelay::Protocol::Udp;
+ case Tcp: return multi::PermitVpnRelay::Protocol::Tcp;
+ case Udp: return multi::PermitVpnRelay::Protocol::Udp;
default:
{
THROW_ERROR("Missing case handler in switch clause");
@@ -48,16 +47,20 @@ baseline::PermitVpnRelay::Protocol TranslateProtocol(WinFwProtocol protocol)
// a local resolver to leave the machine. From the local resolver the request will either be
// resolved from cache, or forwarded out onto the Internet.
//
-// Therefore, whenever the PermitLan rule might be activated, we must also do proper DNS management
-// to prevent leaks.
+// Therefore, we're unconditionally lifting all DNS traffic out of the baseline sublayer and restricting
+// it in the DNS sublayer instead. The PermitDNS rule in the baseline sublayer accomplishes this.
+//
+// This has implications for the way the relay access is configured. In the regular case there
+// is no issue: The PermitVpnRelay rule can be installed in the baseline sublayer.
+//
+// However, if the relay is running on the DNS port (53), it would be blocked unless the DNS
+// sublayer permits this traffic. For this reason, whenever the relay is on port 53, the
+// PermitVpnRelay rule has to be installed to the DNS sublayer instead of the baseline sublayer.
//
void AppendSettingsRules
(
FwContext::Ruleset &ruleset,
- const WinFwSettings &settings,
- std::optional<std::wstring> tunnelInterfaceAlias = std::nullopt,
- std::optional<std::vector<wfp::IpAddress> > nonTunnelDnsServers = std::nullopt,
- std::optional<std::vector<wfp::IpAddress> > tunnelDnsServers = std::nullopt
+ const WinFwSettings &settings
)
{
if (settings.permitDhcp)
@@ -79,18 +82,32 @@ void AppendSettingsRules
ruleset.emplace_back(std::make_unique<baseline::PermitDns>());
ruleset.emplace_back(std::make_unique<dns::BlockAll>());
+}
- if (nonTunnelDnsServers.has_value())
- {
- ruleset.emplace_back(std::make_unique<dns::PermitNonTunnel>(
- tunnelInterfaceAlias, nonTunnelDnsServers.value()));
- }
+//
+// Refer comment on `AppendSettingsRules`.
+//
+void AppendRelayRules
+(
+ FwContext::Ruleset &ruleset,
+ const WinFwRelay &relay,
+ const std::vector<std::wstring> &approvedApplications
+)
+{
+ auto sublayer =
+ (
+ DNS_SERVER_PORT == relay.port
+ ? rules::multi::PermitVpnRelay::Sublayer::Dns
+ : rules::multi::PermitVpnRelay::Sublayer::Baseline
+ );
- if (tunnelInterfaceAlias.has_value() && tunnelDnsServers.has_value())
- {
- ruleset.emplace_back(std::make_unique<dns::PermitTunnel>(
- tunnelInterfaceAlias.value(), tunnelDnsServers.value()));
- }
+ ruleset.emplace_back(std::make_unique<multi::PermitVpnRelay>(
+ wfp::IpAddress(relay.ip),
+ relay.port,
+ TranslateProtocol(relay.protocol),
+ approvedApplications,
+ sublayer
+ ));
}
void AppendNetBlockedRules(FwContext::Ruleset &ruleset)
@@ -99,23 +116,15 @@ void AppendNetBlockedRules(FwContext::Ruleset &ruleset)
ruleset.emplace_back(std::make_unique<baseline::PermitLoopback>());
}
-std::optional<std::vector<wfp::IpAddress> >
-CreateRelayDnsExclusion(const WinFwRelay &relay)
-{
- if (relay.port != DNS_SERVER_PORT)
- {
- return std::nullopt;
- }
-
- std::vector<wfp::IpAddress> result = { wfp::IpAddress(relay.ip) };
-
- return std::move(result);
-}
-
} // anonymous namespace
-FwContext::FwContext(uint32_t timeout)
- : m_baseline(0)
+FwContext::FwContext
+(
+ uint32_t timeout,
+ const std::vector<std::wstring> &approvedApplications
+)
+ : m_approvedApplications(approvedApplications)
+ , m_baseline(0)
, m_activePolicy(Policy::None)
{
auto engine = wfp::FilterEngine::StandardSession(timeout);
@@ -134,8 +143,14 @@ FwContext::FwContext(uint32_t timeout)
m_activePolicy = Policy::None;
}
-FwContext::FwContext(uint32_t timeout, const WinFwSettings &settings)
- : m_baseline(0)
+FwContext::FwContext
+(
+ uint32_t timeout,
+ const WinFwSettings &settings,
+ const std::vector<std::wstring> &approvedApplications
+)
+ : m_approvedApplications(approvedApplications)
+ , m_baseline(0)
, m_activePolicy(Policy::None)
{
auto engine = wfp::FilterEngine::StandardSession(timeout);
@@ -166,13 +181,8 @@ bool FwContext::applyPolicyConnecting
Ruleset ruleset;
AppendNetBlockedRules(ruleset);
- AppendSettingsRules(ruleset, settings, std::nullopt, CreateRelayDnsExclusion(relay));
-
- ruleset.emplace_back(std::make_unique<baseline::PermitVpnRelay>(
- wfp::IpAddress(relay.ip),
- relay.port,
- TranslateProtocol(relay.protocol)
- ));
+ AppendSettingsRules(ruleset, settings);
+ AppendRelayRules(ruleset, relay, m_approvedApplications);
//
// Permit pinging the gateway inside the tunnel.
@@ -208,20 +218,11 @@ bool FwContext::applyPolicyConnected
Ruleset ruleset;
AppendNetBlockedRules(ruleset);
+ AppendSettingsRules(ruleset, settings);
+ AppendRelayRules(ruleset, relay, m_approvedApplications);
- AppendSettingsRules
- (
- ruleset,
- settings,
- std::make_optional<>(tunnelInterfaceAlias),
- CreateRelayDnsExclusion(relay),
- std::make_optional<>(tunnelDnsServers)
- );
-
- ruleset.emplace_back(std::make_unique<baseline::PermitVpnRelay>(
- wfp::IpAddress(relay.ip),
- relay.port,
- TranslateProtocol(relay.protocol)
+ ruleset.emplace_back(std::make_unique<dns::PermitTunnel>(
+ tunnelInterfaceAlias, tunnelDnsServers
));
ruleset.emplace_back(std::make_unique<baseline::PermitVpnTunnel>(
diff --git a/windows/winfw/src/winfw/fwcontext.h b/windows/winfw/src/winfw/fwcontext.h
index 6bdb398b16..fd8871e26b 100644
--- a/windows/winfw/src/winfw/fwcontext.h
+++ b/windows/winfw/src/winfw/fwcontext.h
@@ -13,10 +13,15 @@ class FwContext
{
public:
- FwContext(uint32_t timeout);
+ FwContext(uint32_t timeout, const std::vector<std::wstring> &approvedApplications);
// This ctor applies the "blocked" policy.
- FwContext(uint32_t timeout, const WinFwSettings &settings);
+ FwContext
+ (
+ uint32_t timeout,
+ const WinFwSettings &settings,
+ const std::vector<std::wstring> &approvedApplications
+ );
struct PingableHosts
{
@@ -69,6 +74,8 @@ private:
bool applyRuleset(const Ruleset &ruleset);
bool applyRulesetDirectly(const Ruleset &ruleset, SessionController &controller);
+ const std::vector<std::wstring> m_approvedApplications;
+
std::unique_ptr<SessionController> m_sessionController;
uint32_t m_baseline;
diff --git a/windows/winfw/src/winfw/rules/baseline/permitvpnrelay.h b/windows/winfw/src/winfw/rules/baseline/permitvpnrelay.h
deleted file mode 100644
index 8dd2c630f4..0000000000
--- a/windows/winfw/src/winfw/rules/baseline/permitvpnrelay.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-
-#include <winfw/rules/ifirewallrule.h>
-#include <libwfp/ipaddress.h>
-
-namespace rules::baseline
-{
-
-class PermitVpnRelay : public IFirewallRule
-{
-public:
-
- enum class Protocol
- {
- Tcp,
- Udp
- };
-
- PermitVpnRelay(const wfp::IpAddress &relay, uint16_t relayPort, Protocol protocol);
-
- bool apply(IObjectInstaller &objectInstaller) override;
-
-private:
-
- const wfp::IpAddress m_relay;
- const uint16_t m_relayPort;
- const Protocol m_protocol;
-};
-
-}
diff --git a/windows/winfw/src/winfw/rules/dns/permitnontunnel.h b/windows/winfw/src/winfw/rules/dns/permitnontunnel.h
index 07b67245c3..3d8fac5cf2 100644
--- a/windows/winfw/src/winfw/rules/dns/permitnontunnel.h
+++ b/windows/winfw/src/winfw/rules/dns/permitnontunnel.h
@@ -6,6 +6,11 @@
#include <optional>
#include <string>
+//
+// N.B. This rule must only be used for "custom DNS".
+// Connecting to a relay on port 53 is supported using a different rule.
+//
+
namespace rules::dns
{
@@ -14,8 +19,10 @@ class PermitNonTunnel : public IFirewallRule
public:
//
- // The alias argument has to be optional for when the relay is connected on port 53.
- // At this point in time there's no tunnel yet.
+ // The tunnel alias is optional so this rule can be applied even
+ // when no tunnel exists.
+ //
+ // If a tunnel does exist, the alias must be provided.
//
PermitNonTunnel(std::optional<std::wstring> tunnelInterfaceAlias, const std::vector<wfp::IpAddress> &hosts);
diff --git a/windows/winfw/src/winfw/rules/baseline/permitvpnrelay.cpp b/windows/winfw/src/winfw/rules/multi/permitvpnrelay.cpp
index daa21c3e35..db14ee4852 100644
--- a/windows/winfw/src/winfw/rules/baseline/permitvpnrelay.cpp
+++ b/windows/winfw/src/winfw/rules/multi/permitvpnrelay.cpp
@@ -6,11 +6,12 @@
#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 rules::multi
{
namespace
@@ -42,13 +43,39 @@ std::unique_ptr<ConditionProtocol> CreateProtocolCondition(PermitVpnRelay::Proto
};
}
+const GUID &TranslateSublayer(PermitVpnRelay::Sublayer sublayer)
+{
+ switch (sublayer)
+ {
+ case PermitVpnRelay::Sublayer::Baseline: return MullvadGuids::SublayerBaseline();
+ case PermitVpnRelay::Sublayer::Dns: return MullvadGuids::SublayerDns();
+ default:
+ {
+ THROW_ERROR("Missing case handler in switch clause");
+ }
+ };
+}
+
} // anonymous namespace
-PermitVpnRelay::PermitVpnRelay(const wfp::IpAddress &relay, uint16_t relayPort, Protocol protocol)
+PermitVpnRelay::PermitVpnRelay
+(
+ const wfp::IpAddress &relay,
+ uint16_t relayPort,
+ Protocol protocol,
+ const std::vector<std::wstring> &approvedApplications,
+ Sublayer sublayer
+)
: m_relay(relay)
, m_relayPort(relayPort)
, m_protocol(protocol)
+ , m_approvedApplications(approvedApplications)
+ , m_sublayer(sublayer)
{
+ if (m_approvedApplications.empty())
+ {
+ THROW_ERROR("Cannot configure relay access without list of approved applications");
+ }
}
bool PermitVpnRelay::apply(IObjectInstaller &objectInstaller)
@@ -65,7 +92,7 @@ bool PermitVpnRelay::apply(IObjectInstaller &objectInstaller)
.description(L"This filter is part of a rule that permits communication with a VPN relay")
.provider(MullvadGuids::Provider())
.layer(LayerFromIp(m_relay))
- .sublayer(MullvadGuids::SublayerBaseline())
+ .sublayer(TranslateSublayer(m_sublayer))
.weight(wfp::FilterBuilder::WeightClass::Max)
.permit();
@@ -75,6 +102,11 @@ bool PermitVpnRelay::apply(IObjectInstaller &objectInstaller)
conditionBuilder.add_condition(ConditionPort::Remote(m_relayPort));
conditionBuilder.add_condition(CreateProtocolCondition(m_protocol));
+ for (const auto &app : m_approvedApplications)
+ {
+ conditionBuilder.add_condition(std::make_unique<ConditionApplication>(app));
+ }
+
return objectInstaller.addFilter(filterBuilder, conditionBuilder);
}
diff --git a/windows/winfw/src/winfw/rules/multi/permitvpnrelay.h b/windows/winfw/src/winfw/rules/multi/permitvpnrelay.h
new file mode 100644
index 0000000000..e40fce159d
--- /dev/null
+++ b/windows/winfw/src/winfw/rules/multi/permitvpnrelay.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <winfw/rules/ifirewallrule.h>
+#include <libwfp/ipaddress.h>
+#include <string>
+#include <vector>
+
+namespace rules::multi
+{
+
+class PermitVpnRelay : public IFirewallRule
+{
+public:
+
+ enum class Protocol
+ {
+ Tcp,
+ Udp
+ };
+
+ enum class Sublayer
+ {
+ Baseline,
+ Dns
+ };
+
+ PermitVpnRelay
+ (
+ const wfp::IpAddress &relay,
+ uint16_t relayPort,
+ Protocol protocol,
+ const std::vector<std::wstring> &approvedApplications,
+ Sublayer sublayer
+ );
+
+ bool apply(IObjectInstaller &objectInstaller) override;
+
+private:
+
+ const wfp::IpAddress m_relay;
+ const uint16_t m_relayPort;
+ const Protocol m_protocol;
+ const std::vector<std::wstring> m_approvedApplications;
+ const Sublayer m_sublayer;
+};
+
+}
diff --git a/windows/winfw/src/winfw/winfw.cpp b/windows/winfw/src/winfw/winfw.cpp
index 6c1cc7cd5a..55587e03f9 100644
--- a/windows/winfw/src/winfw/winfw.cpp
+++ b/windows/winfw/src/winfw/winfw.cpp
@@ -42,6 +42,27 @@ std::optional<FwContext::PingableHosts> ConvertPingableHosts(const PingableHosts
return converted;
}
+std::vector<std::wstring> ConvertApprovedApplications
+(
+ WinFwApprovedApplications *approvedApplications
+)
+{
+ if (nullptr == approvedApplications
+ || 0 == approvedApplications->numApps)
+ {
+ THROW_ERROR("Invalid list of approved applications (empty list)");
+ }
+
+ std::vector<std::wstring> converted;
+
+ for (size_t i = 0; i < approvedApplications->numApps; ++i)
+ {
+ converted.emplace_back(std::wstring(approvedApplications->apps[i]));
+ }
+
+ return converted;
+}
+
} // anonymous namespace
WINFW_LINKAGE
@@ -49,6 +70,7 @@ bool
WINFW_API
WinFw_Initialize(
uint32_t timeout,
+ WinFwApprovedApplications *approvedApplications,
MullvadLogSink logSink,
void *logSinkContext
)
@@ -70,7 +92,8 @@ WinFw_Initialize(
g_logSink = logSink;
g_logSinkContext = logSinkContext;
- g_fwContext = new FwContext(timeout_ms);
+ g_fwContext = new FwContext(timeout_ms,
+ ConvertApprovedApplications(approvedApplications));
}
catch (std::exception &err)
{
@@ -96,6 +119,7 @@ WINFW_API
WinFw_InitializeBlocked(
uint32_t timeout,
const WinFwSettings *settings,
+ WinFwApprovedApplications *approvedApplications,
MullvadLogSink logSink,
void *logSinkContext
)
@@ -122,7 +146,8 @@ WinFw_InitializeBlocked(
g_logSink = logSink;
g_logSinkContext = logSinkContext;
- g_fwContext = new FwContext(timeout_ms, *settings);
+ g_fwContext = new FwContext(timeout_ms, *settings,
+ ConvertApprovedApplications(approvedApplications));
}
catch (std::exception &err)
{
diff --git a/windows/winfw/src/winfw/winfw.h b/windows/winfw/src/winfw/winfw.h
index 8f418c333b..100c166d32 100644
--- a/windows/winfw/src/winfw/winfw.h
+++ b/windows/winfw/src/winfw/winfw.h
@@ -45,6 +45,17 @@ typedef struct tag_WinFwRelay
}
WinFwRelay;
+//
+// This structure is used to define the set of applications
+// that are allowed to communicate with the relay.
+//
+typedef struct tag_WinFwApprovedApplications
+{
+ const wchar_t **apps;
+ size_t numApps;
+}
+WinFwApprovedApplications;
+
#pragma pack(pop)
///////////////////////////////////////////////////////////////////////////////
@@ -67,6 +78,7 @@ bool
WINFW_API
WinFw_Initialize(
uint32_t timeout,
+ WinFwApprovedApplications *approvedApplications,
MullvadLogSink logSink,
void *logSinkContext
);
@@ -88,6 +100,7 @@ WINFW_API
WinFw_InitializeBlocked(
uint32_t timeout,
const WinFwSettings *settings,
+ WinFwApprovedApplications *approvedApplications,
MullvadLogSink logSink,
void *logSinkContext
);
diff --git a/windows/winfw/src/winfw/winfw.vcxproj b/windows/winfw/src/winfw/winfw.vcxproj
index c999f5aaca..85a6e0d0b4 100644
--- a/windows/winfw/src/winfw/winfw.vcxproj
+++ b/windows/winfw/src/winfw/winfw.vcxproj
@@ -32,12 +32,12 @@
<ClCompile Include="rules\baseline\permitloopback.cpp" />
<ClCompile Include="rules\baseline\permitndp.cpp" />
<ClCompile Include="rules\baseline\permitping.cpp" />
- <ClCompile Include="rules\baseline\permitvpnrelay.cpp" />
<ClCompile Include="rules\baseline\permitvpntunnel.cpp" />
<ClCompile Include="rules\baseline\permitvpntunnelservice.cpp" />
<ClCompile Include="rules\dns\blockall.cpp" />
<ClCompile Include="rules\dns\permitnontunnel.cpp" />
<ClCompile Include="rules\dns\permittunnel.cpp" />
+ <ClCompile Include="rules\multi\permitvpnrelay.cpp" />
<ClCompile Include="rules\shared.cpp" />
<ClCompile Include="sessioncontroller.cpp" />
<ClCompile Include="sessionrecord.cpp" />
@@ -65,12 +65,12 @@
<ClInclude Include="rules\baseline\permitloopback.h" />
<ClInclude Include="rules\baseline\permitndp.h" />
<ClInclude Include="rules\baseline\permitping.h" />
- <ClInclude Include="rules\baseline\permitvpnrelay.h" />
<ClInclude Include="rules\baseline\permitvpntunnel.h" />
<ClInclude Include="rules\baseline\permitvpntunnelservice.h" />
<ClInclude Include="rules\dns\blockall.h" />
<ClInclude Include="rules\dns\permitnontunnel.h" />
<ClInclude Include="rules\dns\permittunnel.h" />
+ <ClInclude Include="rules\multi\permitvpnrelay.h" />
<ClInclude Include="rules\ports.h" />
<ClInclude Include="rules\shared.h" />
<ClInclude Include="wfpobjecttype.h" />
diff --git a/windows/winfw/src/winfw/winfw.vcxproj.filters b/windows/winfw/src/winfw/winfw.vcxproj.filters
index 46c0594c10..9ac82e87fb 100644
--- a/windows/winfw/src/winfw/winfw.vcxproj.filters
+++ b/windows/winfw/src/winfw/winfw.vcxproj.filters
@@ -34,9 +34,6 @@
<ClCompile Include="rules\baseline\permitping.cpp">
<Filter>rules\baseline</Filter>
</ClCompile>
- <ClCompile Include="rules\baseline\permitvpnrelay.cpp">
- <Filter>rules\baseline</Filter>
- </ClCompile>
<ClCompile Include="rules\baseline\permitvpntunnel.cpp">
<Filter>rules\baseline</Filter>
</ClCompile>
@@ -58,6 +55,9 @@
<ClCompile Include="rules\shared.cpp">
<Filter>rules</Filter>
</ClCompile>
+ <ClCompile Include="rules\multi\permitvpnrelay.cpp">
+ <Filter>rules\multi</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
@@ -99,9 +99,6 @@
<ClInclude Include="rules\baseline\permitping.h">
<Filter>rules\baseline</Filter>
</ClInclude>
- <ClInclude Include="rules\baseline\permitvpnrelay.h">
- <Filter>rules\baseline</Filter>
- </ClInclude>
<ClInclude Include="rules\baseline\permitvpntunnel.h">
<Filter>rules\baseline</Filter>
</ClInclude>
@@ -126,6 +123,9 @@
<ClInclude Include="rules\shared.h">
<Filter>rules</Filter>
</ClInclude>
+ <ClInclude Include="rules\multi\permitvpnrelay.h">
+ <Filter>rules\multi</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="rules">
@@ -137,6 +137,9 @@
<Filter Include="rules\dns">
<UniqueIdentifier>{9b35e8a4-84be-4ac3-9b6f-eb21cc02e065}</UniqueIdentifier>
</Filter>
+ <Filter Include="rules\multi">
+ <UniqueIdentifier>{005cce7c-ed9d-4675-8e4f-759c9682b77e}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<None Include="winfw.def" />