summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJoakim Hulthe <joakim.hulthe@mullvad.net>2025-06-19 15:22:53 +0200
committerDavid Lönnhager <david.l@mullvad.net>2025-06-19 15:47:07 +0200
commit267087b3255e2748693d52728dadfdd69c6cb761 (patch)
tree873c61c4f1eafa3d25bff70b55bc6c40f090fd01
parent69ebc3b8f16d1427c197b2951690bd1f4682362b (diff)
downloadmullvadvpn-267087b3255e2748693d52728dadfdd69c6cb761.tar.xz
mullvadvpn-267087b3255e2748693d52728dadfdd69c6cb761.zip
Do not add split-tunneling fw rules if no net_cls
-rw-r--r--talpid-core/src/firewall/linux.rs31
1 files changed, 27 insertions, 4 deletions
diff --git a/talpid-core/src/firewall/linux.rs b/talpid-core/src/firewall/linux.rs
index 26d3a5cb5a..b72b4c12d6 100644
--- a/talpid-core/src/firewall/linux.rs
+++ b/talpid-core/src/firewall/linux.rs
@@ -12,9 +12,12 @@ use std::{
net::{IpAddr, Ipv4Addr},
sync::LazyLock,
};
-use talpid_types::net::{
- AllowedEndpoint, AllowedTunnelTraffic, Endpoint, TransportProtocol, ALLOWED_LAN_MULTICAST_NETS,
- ALLOWED_LAN_NETS,
+use talpid_types::{
+ cgroup::find_net_cls_mount,
+ net::{
+ AllowedEndpoint, AllowedTunnelTraffic, Endpoint, TransportProtocol,
+ ALLOWED_LAN_MULTICAST_NETS, ALLOWED_LAN_NETS,
+ },
};
/// Priority for rules that tag split tunneling packets. Equals NF_IP_PRI_MANGLE.
@@ -52,6 +55,10 @@ pub enum Error {
/// Unable to translate network interface name into index.
#[error("Unable to translate network interface name \"{0}\" into index")]
LookupIfaceIndexError(String, #[source] crate::linux::IfaceIndexLookupError),
+
+ /// Failed to check if the net_cls mount exists.
+ #[error("An error occurred when checking for net_cls")]
+ FindNetClsMount(#[source] io::Error),
}
/// TODO(linus): This crate is not supposed to be Mullvad-aware. So at some point this should be
@@ -303,7 +310,19 @@ impl<'a> PolicyBatch<'a> {
/// policy.
pub fn finalize(mut self, policy: &FirewallPolicy, fwmark: u32) -> Result<FinalizedBatch> {
self.add_loopback_rules()?;
- self.add_split_tunneling_rules(policy, fwmark)?;
+
+ // if cgroups v1 doesn't exist, split tunneling won't work.
+ // checking if the `net_cls` mount exists is a cheeky way of checking this.
+ if find_net_cls_mount()
+ .map_err(Error::FindNetClsMount)?
+ .is_some()
+ {
+ self.add_split_tunneling_rules(policy, fwmark)?;
+ } else {
+ // skipping add_split_tunneling_rules as it won't cause traffic to leak
+ log::warn!("net_cls mount not found, skipping add_split_tunneling_rules");
+ }
+
self.add_dhcp_client_rules();
self.add_ndp_rules();
self.add_policy_specific_rules(policy, fwmark)?;
@@ -311,6 +330,10 @@ impl<'a> PolicyBatch<'a> {
Ok(self.batch.finalize())
}
+ /// Allow split-tunneled traffic outside the tunnel.
+ ///
+ /// This is acheived by setting `fwmark` on connections initated by processes in the cgroup
+ /// defined by [split_tunnel::NET_CLS_CLASSID].
fn add_split_tunneling_rules(&mut self, policy: &FirewallPolicy, fwmark: u32) -> Result<()> {
// Send select DNS requests in the tunnel
if let FirewallPolicy::Connected {