summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md6
-rw-r--r--docs/security.md8
-rw-r--r--mullvad-daemon/src/lib.rs34
-rw-r--r--talpid-core/src/firewall/linux.rs4
-rw-r--r--talpid-core/src/firewall/macos.rs4
-rw-r--r--talpid-core/src/firewall/mod.rs13
-rw-r--r--talpid-core/src/firewall/windows.rs111
-rw-r--r--talpid-core/src/tunnel_state_machine/mod.rs22
-rw-r--r--talpid-types/src/net/mod.rs34
-rw-r--r--windows/winfw/src/winfw/fwcontext.cpp25
-rw-r--r--windows/winfw/src/winfw/fwcontext.h10
-rw-r--r--windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp6
-rw-r--r--windows/winfw/src/winfw/rules/baseline/permitendpoint.h3
-rw-r--r--windows/winfw/src/winfw/winfw.cpp6
-rw-r--r--windows/winfw/src/winfw/winfw.h20
15 files changed, 218 insertions, 88 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3123022759..6df7d9ca18 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -56,6 +56,12 @@ Line wrap the file at 100 chars. Th
- Fix banner sometimes incorrectly showing (e.g. "BLOCKING INTERNET").
- Fix issue with the user getting kicked out of certain views in settings when the app is brought to the foreground.
+### Security
+#### Windows
+- Restrict which applications are allowed to communicate with the API while in a blocking state.
+ This prevents malicious scripts on websites from trying to do so.
+
+
## [2021.6] - 2021-11-17
### Fixed
- Fix the font for Russian. Issue introduced in 2021.6-beta1.
diff --git a/docs/security.md b/docs/security.md
index 2f0b09e31c..67d4f3dcdf 100644
--- a/docs/security.md
+++ b/docs/security.md
@@ -99,6 +99,13 @@ The following network traffic is allowed or blocked independent of state:
On Linux, any situation that permits incoming or outgoing traffic also allows that traffic to be
forwarded. All other forward traffic is rejected.
+#### Mullvad API
+
+The firewall allows traffic for the API regardless of tunnel state, to allow for updating keys,
+fetching account data, etc. In the [Connected] state, this is only allowed inside the tunnel.
+For the other states, it is allowed regardless. On Windows, only the Mullvad service and problem
+report tool are able to communicate with the API in any of the blocking states.
+
### Disconnected
This is the default state that the `mullvad-daemon` starts in when the device boots, unless
@@ -184,7 +191,6 @@ disconnect/quit is explicitly requested by the user. At the same time there migh
when the app can't establish a tunnel for the device. This includes, but is not limited to:
* Account runs out of time
* The computer is offline
-* the TAP adapter driver has an error or the adapter can't be found (Windows)
* Some internal error parsing or modifying system routing table, DNS settings etc.
In the above cases the app gives up trying to create a tunnel, but it can't go to the
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index b0292b4a8b..5557590b09 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -64,7 +64,10 @@ use talpid_core::{
#[cfg(target_os = "android")]
use talpid_types::android::AndroidContext;
use talpid_types::{
- net::{openvpn, Endpoint, TransportProtocol, TunnelEndpoint, TunnelParameters, TunnelType},
+ net::{
+ openvpn, AllowedEndpoint, Endpoint, TransportProtocol, TunnelEndpoint, TunnelParameters,
+ TunnelType,
+ },
tunnel::{ErrorStateCause, ParameterGenerationError, TunnelStateTransition},
ErrorExt,
};
@@ -640,10 +643,8 @@ where
let api_availability = rpc_runtime.availability_handle();
api_availability.suspend();
- let initial_api_endpoint = Endpoint::from_socket_address(
- rpc_runtime.address_cache.peek_address(),
- TransportProtocol::Tcp,
- );
+ let initial_api_endpoint =
+ Self::get_allowed_endpoint(rpc_runtime.address_cache.peek_address());
let (offline_state_tx, offline_state_rx) = mpsc::unbounded();
let tunnel_command_tx = tunnel_state_machine::spawn(
@@ -676,7 +677,7 @@ where
address_change_runtime.block_on(async move {
if let Some(tx) = tx.upgrade() {
let _ = tx.unbounded_send(TunnelCommand::AllowEndpoint(
- Endpoint::from_socket_address(address, TransportProtocol::Tcp),
+ Self::get_allowed_endpoint(address),
result_tx,
));
result_rx.await.map_err(|_| ())
@@ -770,6 +771,27 @@ where
Ok(daemon)
}
+ fn get_allowed_endpoint(api_address: std::net::SocketAddr) -> AllowedEndpoint {
+ let endpoint = Endpoint::from_socket_address(api_address, TransportProtocol::Tcp);
+
+ #[cfg(windows)]
+ let daemon_exe = std::env::current_exe().expect("failed to obtain executable path");
+ #[cfg(windows)]
+ let clients = vec![
+ daemon_exe
+ .parent()
+ .expect("missing executable parent directory")
+ .join("mullvad-problem-report.exe"),
+ daemon_exe,
+ ];
+
+ AllowedEndpoint {
+ #[cfg(windows)]
+ clients,
+ endpoint,
+ }
+ }
+
fn get_dns_resolvers(options: &DnsOptions) -> Option<Vec<IpAddr>> {
match options.state {
DnsState::Default => {
diff --git a/talpid-core/src/firewall/linux.rs b/talpid-core/src/firewall/linux.rs
index c1619f0f46..c10aba6ba8 100644
--- a/talpid-core/src/firewall/linux.rs
+++ b/talpid-core/src/firewall/linux.rs
@@ -560,7 +560,7 @@ impl<'a> PolicyBatch<'a> {
allowed_endpoint,
} => {
self.add_allow_tunnel_endpoint_rules(peer_endpoint);
- self.add_allow_endpoint_rules(allowed_endpoint);
+ self.add_allow_endpoint_rules(&allowed_endpoint.endpoint);
// Important to block DNS after allow relay rule (so the relay can operate
// over port 53) but before allow LAN (so DNS does not leak to the LAN)
@@ -596,7 +596,7 @@ impl<'a> PolicyBatch<'a> {
allow_lan,
allowed_endpoint,
} => {
- self.add_allow_endpoint_rules(allowed_endpoint);
+ self.add_allow_endpoint_rules(&allowed_endpoint.endpoint);
// Important to drop DNS before allowing LAN (to stop DNS leaking to the LAN)
self.add_drop_dns_rule();
diff --git a/talpid-core/src/firewall/macos.rs b/talpid-core/src/firewall/macos.rs
index 3cb63e485e..6cbdbbf7ff 100644
--- a/talpid-core/src/firewall/macos.rs
+++ b/talpid-core/src/firewall/macos.rs
@@ -104,7 +104,7 @@ impl Firewall {
allowed_endpoint,
} => {
let mut rules = vec![self.get_allow_relay_rule(peer_endpoint)?];
- rules.push(self.get_allowed_endpoint_rule(allowed_endpoint)?);
+ rules.push(self.get_allowed_endpoint_rule(allowed_endpoint.endpoint)?);
// Important to block DNS after allow relay rule (so the relay can operate
// over port 53) but before allow LAN (so DNS does not leak to the LAN)
@@ -150,7 +150,7 @@ impl Firewall {
allowed_endpoint,
} => {
let mut rules = Vec::new();
- rules.push(self.get_allowed_endpoint_rule(allowed_endpoint)?);
+ rules.push(self.get_allowed_endpoint_rule(allowed_endpoint.endpoint)?);
if allow_lan {
// Important to block DNS before allow LAN (so DNS does not leak to the LAN)
rules.append(&mut self.get_block_dns_rules()?);
diff --git a/talpid-core/src/firewall/mod.rs b/talpid-core/src/firewall/mod.rs
index 380953f7c5..46bcf27745 100644
--- a/talpid-core/src/firewall/mod.rs
+++ b/talpid-core/src/firewall/mod.rs
@@ -9,7 +9,7 @@ use std::net::IpAddr;
use std::net::{Ipv4Addr, Ipv6Addr};
#[cfg(windows)]
use std::path::PathBuf;
-use talpid_types::net::Endpoint;
+use talpid_types::net::{AllowedEndpoint, Endpoint};
#[cfg(target_os = "macos")]
#[path = "macos.rs"]
@@ -107,8 +107,8 @@ pub enum FirewallPolicy {
tunnel: Option<crate::tunnel::TunnelMetadata>,
/// Flag setting if communication with LAN networks should be possible.
allow_lan: bool,
- /// Host that should be reachable by the tunnel client while connecting.
- allowed_endpoint: Endpoint,
+ /// Host that should be reachable while connecting.
+ allowed_endpoint: AllowedEndpoint,
/// A process that is allowed to send packets to the relay.
#[cfg(windows)]
relay_client: PathBuf,
@@ -135,7 +135,7 @@ pub enum FirewallPolicy {
/// Flag setting if communication with LAN networks should be possible.
allow_lan: bool,
/// Host that should be reachable while in the blocked state.
- allowed_endpoint: Endpoint,
+ allowed_endpoint: AllowedEndpoint,
},
}
@@ -225,10 +225,7 @@ pub enum InitialFirewallState {
/// Do not set any policy.
None,
/// Atomically enter the blocked state.
- Blocked {
- /// Host that should be reachable while in the blocked state.
- allowed_endpoint: Endpoint,
- },
+ Blocked(AllowedEndpoint),
}
impl Firewall {
diff --git a/talpid-core/src/firewall/windows.rs b/talpid-core/src/firewall/windows.rs
index 3bb201507c..989e453ff7 100644
--- a/talpid-core/src/firewall/windows.rs
+++ b/talpid-core/src/firewall/windows.rs
@@ -6,7 +6,10 @@ use self::winfw::*;
use super::{FirewallArguments, FirewallPolicy, FirewallT, InitialFirewallState};
use crate::winnet;
use log::{debug, error, trace};
-use talpid_types::{net::Endpoint, tunnel::FirewallPolicyError};
+use talpid_types::{
+ net::{AllowedEndpoint, Endpoint},
+ tunnel::FirewallPolicyError,
+};
use widestring::WideCString;
/// Errors that can happen when configuring the Windows firewall.
@@ -53,19 +56,14 @@ impl FirewallT for Firewall {
fn new(args: FirewallArguments) -> Result<Self, Self::Error> {
let logging_context = b"WinFw\0".as_ptr();
- if let InitialFirewallState::Blocked { allowed_endpoint } = args.initial_state {
+ if let InitialFirewallState::Blocked(allowed_endpoint) = args.initial_state {
let cfg = &WinFwSettings::new(args.allow_lan);
- let allowed_endpoint_ip = widestring_ip(allowed_endpoint.address.ip());
- let winfw_allowed_endpoint = WinFwEndpoint {
- ip: allowed_endpoint_ip.as_ptr(),
- port: allowed_endpoint.address.port(),
- protocol: WinFwProt::from(allowed_endpoint.protocol),
- };
+ let allowed_endpoint = WinFwAllowedEndpointContainer::from(allowed_endpoint);
unsafe {
WinFw_InitializeBlocked(
WINFW_TIMEOUT_SECONDS,
&cfg,
- &winfw_allowed_endpoint,
+ &allowed_endpoint.as_endpoint(),
Some(log_sink),
logging_context,
)
@@ -92,11 +90,12 @@ impl FirewallT for Firewall {
relay_client,
} => {
let cfg = &WinFwSettings::new(allow_lan);
+
self.set_connecting_state(
&peer_endpoint,
&cfg,
&tunnel,
- &allowed_endpoint,
+ &WinFwAllowedEndpointContainer::from(allowed_endpoint).as_endpoint(),
&relay_client,
)
}
@@ -115,7 +114,10 @@ impl FirewallT for Firewall {
allowed_endpoint,
} => {
let cfg = &WinFwSettings::new(allow_lan);
- self.set_blocked_state(&cfg, &allowed_endpoint)
+ self.set_blocked_state(
+ &cfg,
+ &WinFwAllowedEndpointContainer::from(allowed_endpoint).as_endpoint(),
+ )
}
}
}
@@ -146,7 +148,7 @@ impl Firewall {
endpoint: &Endpoint,
winfw_settings: &WinFwSettings,
tunnel_metadata: &Option<TunnelMetadata>,
- allowed_endpoint: &Endpoint,
+ allowed_endpoint: &WinFwAllowedEndpoint<'_>,
relay_client: &Path,
) -> Result<(), Error> {
trace!("Applying 'connecting' firewall policy");
@@ -159,13 +161,6 @@ impl Firewall {
let relay_client = WideCString::from_os_str_truncate(relay_client);
- let allowed_endpoint_ip = widestring_ip(allowed_endpoint.address.ip());
- let winfw_allowed_endpoint = WinFwEndpoint {
- ip: allowed_endpoint_ip.as_ptr(),
- port: allowed_endpoint.address.port(),
- protocol: WinFwProt::from(allowed_endpoint.protocol),
- };
-
let interface_wstr = tunnel_metadata
.as_ref()
.map(|metadata| WideCString::from_str_truncate(&metadata.interface));
@@ -181,7 +176,7 @@ impl Firewall {
&winfw_relay,
relay_client.as_ptr(),
interface_wstr_ptr,
- &winfw_allowed_endpoint,
+ allowed_endpoint,
)
.into_result()
.map_err(Error::ApplyingConnectingPolicy)
@@ -251,19 +246,11 @@ impl Firewall {
fn set_blocked_state(
&mut self,
winfw_settings: &WinFwSettings,
- allowed_endpoint: &Endpoint,
+ allowed_endpoint: &WinFwAllowedEndpoint<'_>,
) -> Result<(), Error> {
trace!("Applying 'blocked' firewall policy");
-
- let allowed_endpoint_ip = widestring_ip(allowed_endpoint.address.ip());
- let winfw_allowed_endpoint = WinFwEndpoint {
- ip: allowed_endpoint_ip.as_ptr(),
- port: allowed_endpoint.address.port(),
- protocol: WinFwProt::from(allowed_endpoint.protocol),
- };
-
unsafe {
- WinFw_ApplyPolicyBlocked(winfw_settings, &winfw_allowed_endpoint)
+ WinFw_ApplyPolicyBlocked(winfw_settings, allowed_endpoint)
.into_result()
.map_err(Error::ApplyingBlockedPolicy)
}
@@ -276,11 +263,67 @@ fn widestring_ip(ip: IpAddr) -> WideCString {
#[allow(non_snake_case)]
mod winfw {
- use super::Error;
+ use super::{widestring_ip, AllowedEndpoint, Error, WideCString};
use crate::logging::windows::LogSink;
use libc;
use talpid_types::net::TransportProtocol;
+ pub struct WinFwAllowedEndpointContainer {
+ _clients: Box<[WideCString]>,
+ clients_ptrs: Box<[*const u16]>,
+ ip: WideCString,
+ port: u16,
+ protocol: WinFwProt,
+ }
+
+ impl From<AllowedEndpoint> for WinFwAllowedEndpointContainer {
+ fn from(endpoint: AllowedEndpoint) -> Self {
+ let clients = endpoint
+ .clients
+ .iter()
+ .map(|client| WideCString::from_os_str_truncate(client))
+ .collect::<Box<_>>();
+ let clients_ptrs = clients
+ .iter()
+ .map(|client| client.as_ptr())
+ .collect::<Box<_>>();
+ let ip = widestring_ip(endpoint.endpoint.address.ip());
+
+ WinFwAllowedEndpointContainer {
+ _clients: clients,
+ clients_ptrs,
+ ip,
+ port: endpoint.endpoint.address.port(),
+ protocol: WinFwProt::from(endpoint.endpoint.protocol),
+ }
+ }
+ }
+
+ impl WinFwAllowedEndpointContainer {
+ pub fn as_endpoint(&self) -> WinFwAllowedEndpoint<'_> {
+ WinFwAllowedEndpoint {
+ num_clients: self.clients_ptrs.len() as u32,
+ clients: self.clients_ptrs.as_ptr(),
+ endpoint: WinFwEndpoint {
+ ip: self.ip.as_ptr(),
+ port: self.port,
+ protocol: self.protocol,
+ },
+
+ _phantom: std::marker::PhantomData,
+ }
+ }
+ }
+
+ #[repr(C)]
+ pub struct WinFwAllowedEndpoint<'a> {
+ num_clients: u32,
+ clients: *const *const libc::wchar_t,
+ endpoint: WinFwEndpoint,
+
+ _phantom: std::marker::PhantomData<&'a WinFwAllowedEndpointContainer>,
+ }
+
#[repr(C)]
pub struct WinFwEndpoint {
pub ip: *const libc::wchar_t,
@@ -370,7 +413,7 @@ mod winfw {
pub fn WinFw_InitializeBlocked(
timeout: libc::c_uint,
settings: &WinFwSettings,
- allowed_endpoint: *const WinFwEndpoint,
+ allowed_endpoint: *const WinFwAllowedEndpoint<'_>,
sink: Option<LogSink>,
sink_context: *const u8,
) -> InitializationResult;
@@ -384,7 +427,7 @@ mod winfw {
relay: &WinFwEndpoint,
relayClient: *const libc::wchar_t,
tunnelIfaceAlias: *const libc::wchar_t,
- allowed_endpoint: *const WinFwEndpoint,
+ allowed_endpoint: *const WinFwAllowedEndpoint<'_>,
) -> WinFwPolicyStatus;
#[link_name = "WinFw_ApplyPolicyConnected"]
@@ -402,7 +445,7 @@ mod winfw {
#[link_name = "WinFw_ApplyPolicyBlocked"]
pub fn WinFw_ApplyPolicyBlocked(
settings: &WinFwSettings,
- allowed_endpoint: *const WinFwEndpoint,
+ allowed_endpoint: *const WinFwAllowedEndpoint<'_>,
) -> WinFwPolicyStatus;
#[link_name = "WinFw_Reset"]
diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs
index 671148fde0..5f33d264ca 100644
--- a/talpid-core/src/tunnel_state_machine/mod.rs
+++ b/talpid-core/src/tunnel_state_machine/mod.rs
@@ -34,7 +34,7 @@ use std::{collections::HashSet, io, net::IpAddr, path::PathBuf, sync::Arc};
#[cfg(target_os = "android")]
use talpid_types::{android::AndroidContext, ErrorExt};
use talpid_types::{
- net::{Endpoint, TunnelParameters},
+ net::{AllowedEndpoint, TunnelParameters},
tunnel::{ErrorStateCause, ParameterGenerationError, TunnelStateTransition},
};
@@ -81,7 +81,7 @@ pub struct InitialTunnelState {
pub dns_servers: Option<Vec<IpAddr>>,
/// A single endpoint that is allowed to communicate outside the tunnel, i.e.
/// in any of the blocking states.
- pub allowed_endpoint: Endpoint,
+ pub allowed_endpoint: AllowedEndpoint,
/// Whether to reset any existing firewall rules when initializing the disconnected state.
pub reset_firewall: bool,
/// Programs to exclude from the tunnel using the split tunnel driver.
@@ -109,7 +109,7 @@ pub async fn spawn(
#[cfg(target_os = "android")]
initial_settings.allow_lan,
#[cfg(target_os = "android")]
- initial_settings.allowed_endpoint.address.ip(),
+ initial_settings.allowed_endpoint.endpoint.address.ip(),
#[cfg(target_os = "android")]
initial_settings.dns_servers.clone(),
);
@@ -145,7 +145,7 @@ pub enum TunnelCommand {
AllowLan(bool),
/// Endpoint that should never be blocked.
/// If an error occurs, the sender is dropped.
- AllowEndpoint(Endpoint, oneshot::Sender<()>),
+ AllowEndpoint(AllowedEndpoint, oneshot::Sender<()>),
/// Set DNS servers to use.
Dns(Option<Vec<IpAddr>>),
/// Enable or disable the block_when_disconnected feature.
@@ -209,9 +209,7 @@ impl TunnelStateMachine {
let args = FirewallArguments {
initial_state: if settings.block_when_disconnected || !settings.reset_firewall {
- InitialFirewallState::Blocked {
- allowed_endpoint: settings.allowed_endpoint,
- }
+ InitialFirewallState::Blocked(settings.allowed_endpoint.clone())
} else {
InitialFirewallState::None
},
@@ -356,7 +354,7 @@ struct SharedTunnelStateValues {
/// DNS servers to use (overriding default).
dns_servers: Option<Vec<IpAddr>>,
/// Endpoint that should not be blocked by the firewall.
- allowed_endpoint: Endpoint,
+ allowed_endpoint: AllowedEndpoint,
/// The generator of new `TunnelParameter`s
tunnel_parameters_generator: Box<dyn TunnelParametersGenerator>,
/// The provider of tunnel devices.
@@ -394,13 +392,13 @@ impl SharedTunnelStateValues {
Ok(())
}
- pub fn set_allowed_endpoint(&mut self, endpoint: Endpoint) -> bool {
+ pub fn set_allowed_endpoint(&mut self, endpoint: AllowedEndpoint) -> bool {
if self.allowed_endpoint != endpoint {
- self.allowed_endpoint = endpoint;
-
#[cfg(target_os = "android")]
self.tun_provider
- .set_allowed_endpoint(endpoint.address.ip());
+ .set_allowed_endpoint(endpoint.endpoint.address.ip());
+
+ self.allowed_endpoint = endpoint;
true
} else {
diff --git a/talpid-types/src/net/mod.rs b/talpid-types/src/net/mod.rs
index c03aac3d58..e758d0e02f 100644
--- a/talpid-types/src/net/mod.rs
+++ b/talpid-types/src/net/mod.rs
@@ -1,6 +1,8 @@
#[cfg(target_os = "android")]
use jnix::IntoJava;
use serde::{Deserialize, Serialize};
+#[cfg(windows)]
+use std::path::PathBuf;
use std::{
fmt,
net::{IpAddr, SocketAddr},
@@ -174,6 +176,38 @@ impl fmt::Display for Endpoint {
}
}
+/// Host that should be reachable in any tunnel state.
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct AllowedEndpoint {
+ /// Paths that should be allowed to communicate with `endpoint`.
+ #[cfg(windows)]
+ pub clients: Vec<PathBuf>,
+ pub endpoint: Endpoint,
+}
+
+impl fmt::Display for AllowedEndpoint {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ #[cfg(not(windows))]
+ write!(f, "{}", self.endpoint)?;
+ #[cfg(windows)]
+ {
+ write!(f, "{} for", self.endpoint)?;
+ #[cfg(windows)]
+ for client in &self.clients {
+ write!(
+ f,
+ " {}",
+ client
+ .file_name()
+ .map(|s| s.to_string_lossy())
+ .unwrap_or(std::borrow::Cow::Borrowed("<UNKNOWN>"))
+ )?;
+ }
+ }
+ Ok(())
+ }
+}
+
/// IP protocol version.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
diff --git a/windows/winfw/src/winfw/fwcontext.cpp b/windows/winfw/src/winfw/fwcontext.cpp
index 6f2667c429..fe6c227e7f 100644
--- a/windows/winfw/src/winfw/fwcontext.cpp
+++ b/windows/winfw/src/winfw/fwcontext.cpp
@@ -104,13 +104,20 @@ void AppendRelayRules
void AppendAllowedEndpointRules
(
FwContext::Ruleset &ruleset,
- const WinFwEndpoint &endpoint
+ const WinFwAllowedEndpoint &endpoint
)
{
+ std::vector<std::wstring> clients;
+ clients.reserve(endpoint.numClients);
+ for (uint32_t i = 0; i < endpoint.numClients; i++) {
+ clients.push_back(endpoint.clients[i]);
+ }
+
ruleset.emplace_back(std::make_unique<baseline::PermitEndpoint>(
- wfp::IpAddress(endpoint.ip),
- endpoint.port,
- endpoint.protocol
+ wfp::IpAddress(endpoint.endpoint.ip),
+ clients,
+ endpoint.endpoint.port,
+ endpoint.endpoint.protocol
));
}
@@ -149,7 +156,7 @@ FwContext::FwContext
(
uint32_t timeout,
const WinFwSettings &settings,
- const std::optional<WinFwEndpoint> &allowedEndpoint
+ const std::optional<WinFwAllowedEndpoint> &allowedEndpoint
)
: m_baseline(0)
, m_activePolicy(Policy::None)
@@ -178,7 +185,7 @@ bool FwContext::applyPolicyConnecting
const WinFwEndpoint &relay,
const std::wstring &relayClient,
const std::optional<std::wstring> &tunnelInterfaceAlias,
- const std::optional<WinFwEndpoint> &allowedEndpoint
+ const std::optional<WinFwAllowedEndpoint> &allowedEndpoint
)
{
Ruleset ruleset;
@@ -260,7 +267,7 @@ bool FwContext::applyPolicyConnected
return status;
}
-bool FwContext::applyPolicyBlocked(const WinFwSettings &settings, const std::optional<WinFwEndpoint> &allowedEndpoint)
+bool FwContext::applyPolicyBlocked(const WinFwSettings &settings, const std::optional<WinFwAllowedEndpoint> &allowedEndpoint)
{
const auto status = applyRuleset(composePolicyBlocked(settings, allowedEndpoint));
@@ -292,7 +299,7 @@ FwContext::Policy FwContext::activePolicy() const
return m_activePolicy;
}
-FwContext::Ruleset FwContext::composePolicyBlocked(const WinFwSettings &settings, const std::optional<WinFwEndpoint> &allowedEndpoint)
+FwContext::Ruleset FwContext::composePolicyBlocked(const WinFwSettings &settings, const std::optional<WinFwAllowedEndpoint> &allowedEndpoint)
{
Ruleset ruleset;
@@ -315,7 +322,7 @@ bool FwContext::applyBaseConfiguration()
});
}
-bool FwContext::applyBlockedBaseConfiguration(const WinFwSettings &settings, const std::optional<WinFwEndpoint> &allowedEndpoint, uint32_t &checkpoint)
+bool FwContext::applyBlockedBaseConfiguration(const WinFwSettings &settings, const std::optional<WinFwAllowedEndpoint> &allowedEndpoint, uint32_t &checkpoint)
{
return m_sessionController->executeTransaction([&](SessionController &controller, wfp::FilterEngine &engine)
{
diff --git a/windows/winfw/src/winfw/fwcontext.h b/windows/winfw/src/winfw/fwcontext.h
index a3b23f2c8b..bf67565993 100644
--- a/windows/winfw/src/winfw/fwcontext.h
+++ b/windows/winfw/src/winfw/fwcontext.h
@@ -21,7 +21,7 @@ public:
(
uint32_t timeout,
const WinFwSettings &settings,
- const std::optional<WinFwEndpoint> &allowedEndpoint
+ const std::optional<WinFwAllowedEndpoint> &allowedEndpoint
);
bool applyPolicyConnecting
@@ -30,7 +30,7 @@ public:
const WinFwEndpoint &relay,
const std::wstring &relayClient,
const std::optional<std::wstring> &tunnelInterfaceAlias,
- const std::optional<WinFwEndpoint> &allowedEndpoint
+ const std::optional<WinFwAllowedEndpoint> &allowedEndpoint
);
bool applyPolicyConnected
@@ -45,7 +45,7 @@ public:
bool applyPolicyBlocked(
const WinFwSettings &settings,
- const std::optional<WinFwEndpoint> &allowedEndpoint
+ const std::optional<WinFwAllowedEndpoint> &allowedEndpoint
);
bool reset();
@@ -67,10 +67,10 @@ private:
FwContext(const FwContext &) = delete;
FwContext &operator=(const FwContext &) = delete;
- Ruleset composePolicyBlocked(const WinFwSettings &settings, const std::optional<WinFwEndpoint> &allowedEndpoint);
+ Ruleset composePolicyBlocked(const WinFwSettings &settings, const std::optional<WinFwAllowedEndpoint> &allowedEndpoint);
bool applyBaseConfiguration();
- bool applyBlockedBaseConfiguration(const WinFwSettings &settings, const std::optional<WinFwEndpoint> &allowedEndpoint, uint32_t &checkpoint);
+ bool applyBlockedBaseConfiguration(const WinFwSettings &settings, const std::optional<WinFwAllowedEndpoint> &allowedEndpoint, uint32_t &checkpoint);
bool applyCommonBaseConfiguration(SessionController &controller, wfp::FilterEngine &engine);
bool applyRuleset(const Ruleset &ruleset);
diff --git a/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp b/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp
index 5b79d64ceb..09d8937535 100644
--- a/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp
+++ b/windows/winfw/src/winfw/rules/baseline/permitendpoint.cpp
@@ -48,10 +48,12 @@ std::unique_ptr<ConditionProtocol> CreateProtocolCondition(WinFwProtocol protoco
PermitEndpoint::PermitEndpoint
(
const wfp::IpAddress &address,
+ const std::vector<std::wstring> &clients,
uint16_t port,
WinFwProtocol protocol
)
: m_address(address)
+ , m_clients(clients)
, m_port(port)
, m_protocol(protocol)
{
@@ -81,6 +83,10 @@ bool PermitEndpoint::apply(IObjectInstaller &objectInstaller)
conditionBuilder.add_condition(ConditionPort::Remote(m_port));
conditionBuilder.add_condition(CreateProtocolCondition(m_protocol));
+ for (const auto client : m_clients) {
+ conditionBuilder.add_condition(std::make_unique<ConditionApplication>(client));
+ }
+
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
index 93564dbd1e..9e5e2fc923 100644
--- a/windows/winfw/src/winfw/rules/baseline/permitendpoint.h
+++ b/windows/winfw/src/winfw/rules/baseline/permitendpoint.h
@@ -3,6 +3,7 @@
#include <winfw/rules/ifirewallrule.h>
#include <winfw/winfw.h>
#include <libwfp/ipaddress.h>
+#include <vector>
#include <string>
namespace rules::baseline
@@ -15,6 +16,7 @@ public:
PermitEndpoint
(
const wfp::IpAddress &address,
+ const std::vector<std::wstring> &clients,
uint16_t port,
WinFwProtocol protocol
);
@@ -24,6 +26,7 @@ public:
private:
const wfp::IpAddress m_address;
+ const std::vector<std::wstring> m_clients;
const uint16_t m_port;
const WinFwProtocol m_protocol;
};
diff --git a/windows/winfw/src/winfw/winfw.cpp b/windows/winfw/src/winfw/winfw.cpp
index 57610409c4..ae0f0791de 100644
--- a/windows/winfw/src/winfw/winfw.cpp
+++ b/windows/winfw/src/winfw/winfw.cpp
@@ -118,7 +118,7 @@ WINFW_API
WinFw_InitializeBlocked(
uint32_t timeout,
const WinFwSettings *settings,
- const WinFwEndpoint *allowedEndpoint,
+ const WinFwAllowedEndpoint *allowedEndpoint,
MullvadLogSink logSink,
void *logSinkContext
)
@@ -233,7 +233,7 @@ WinFw_ApplyPolicyConnecting(
const WinFwEndpoint *relay,
const wchar_t *relayClient,
const wchar_t *tunnelInterfaceAlias,
- const WinFwEndpoint *allowedEndpoint
+ const WinFwAllowedEndpoint *allowedEndpoint
)
{
if (nullptr == g_fwContext)
@@ -433,7 +433,7 @@ WINFW_POLICY_STATUS
WINFW_API
WinFw_ApplyPolicyBlocked(
const WinFwSettings *settings,
- const WinFwEndpoint *allowedEndpoint
+ const WinFwAllowedEndpoint *allowedEndpoint
)
{
if (nullptr == g_fwContext)
diff --git a/windows/winfw/src/winfw/winfw.h b/windows/winfw/src/winfw/winfw.h
index 5a34b7784b..4913ae7baf 100644
--- a/windows/winfw/src/winfw/winfw.h
+++ b/windows/winfw/src/winfw/winfw.h
@@ -19,8 +19,6 @@
// Structures
///////////////////////////////////////////////////////////////////////////////
-#pragma pack(push, 1)
-
typedef struct tag_WinFwSettings
{
// Permit outbound DHCP requests and inbound DHCP responses on all interfaces.
@@ -45,7 +43,17 @@ typedef struct tag_WinFwEndpoint
}
WinFwEndpoint;
-#pragma pack(pop)
+typedef struct tag_WinFwAllowedEndpoint
+{
+ uint32_t numClients;
+
+ // A list of paths that are allowed to reach the given endpoint,
+ // even when traffic would otherwise be blocked.
+ const wchar_t **clients;
+
+ WinFwEndpoint endpoint;
+}
+WinFwAllowedEndpoint;
///////////////////////////////////////////////////////////////////////////////
// Functions
@@ -88,7 +96,7 @@ WINFW_API
WinFw_InitializeBlocked(
uint32_t timeout,
const WinFwSettings *settings,
- const WinFwEndpoint *allowedEndpoint,
+ const WinFwAllowedEndpoint *allowedEndpoint,
MullvadLogSink logSink,
void *logSinkContext
);
@@ -142,7 +150,7 @@ WinFw_ApplyPolicyConnecting(
const WinFwEndpoint *relay,
const wchar_t *relayClient,
const wchar_t *tunnelInterfaceAlias,
- const WinFwEndpoint *allowedEndpoint
+ const WinFwAllowedEndpoint *allowedEndpoint
);
//
@@ -189,7 +197,7 @@ WINFW_POLICY_STATUS
WINFW_API
WinFw_ApplyPolicyBlocked(
const WinFwSettings *settings,
- const WinFwEndpoint *allowedEndpoint
+ const WinFwAllowedEndpoint *allowedEndpoint
);
//