summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--talpid-core/src/firewall/macos.rs9
-rw-r--r--talpid-core/src/firewall/mod.rs14
-rw-r--r--talpid-core/src/split_tunnel/macos/tun.rs18
4 files changed, 41 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 610890b245..5e7cbb2bba 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,6 +41,7 @@ Line wrap the file at 100 chars. Th
#### macOS
- Fix Apple services not working by forcing stray connections out through the VPN tunnel. The
"bypass" toggle has been removed.
+- Fix packets being duplicated on LAN when split tunneling is enabled.
## [2024.6-beta1] - 2024-09-26
diff --git a/talpid-core/src/firewall/macos.rs b/talpid-core/src/firewall/macos.rs
index 5f674f2935..73308d8dd9 100644
--- a/talpid-core/src/firewall/macos.rs
+++ b/talpid-core/src/firewall/macos.rs
@@ -119,6 +119,15 @@ impl Firewall {
}
}
+ if let Some(endpoint) = policy.allowed_endpoint() {
+ // Keep states to the allowed endpoint.
+ // Note that we're not taking into account allowed clients here, because it's highly
+ // impractical.
+ if endpoint.endpoint.address == remote_address {
+ return Ok(false);
+ }
+ }
+
let Some(peer) = policy.peer_endpoint().map(|endpoint| endpoint.endpoint) else {
// If there's no peer, there's also no tunnel. We have no states to preserve
return Ok(true);
diff --git a/talpid-core/src/firewall/mod.rs b/talpid-core/src/firewall/mod.rs
index 17f74b17ee..0934972809 100644
--- a/talpid-core/src/firewall/mod.rs
+++ b/talpid-core/src/firewall/mod.rs
@@ -143,6 +143,20 @@ impl FirewallPolicy {
}
}
+ /// Return the allowed endpoint, if available
+ pub fn allowed_endpoint(&self) -> Option<&AllowedEndpoint> {
+ match self {
+ FirewallPolicy::Connecting {
+ allowed_endpoint, ..
+ }
+ | FirewallPolicy::Blocked {
+ allowed_endpoint: Some(allowed_endpoint),
+ ..
+ } => Some(allowed_endpoint),
+ _ => None,
+ }
+ }
+
/// Return tunnel metadata, if available
pub fn tunnel(&self) -> Option<&crate::tunnel::TunnelMetadata> {
match self {
diff --git a/talpid-core/src/split_tunnel/macos/tun.rs b/talpid-core/src/split_tunnel/macos/tun.rs
index 0e260a1517..90581c736c 100644
--- a/talpid-core/src/split_tunnel/macos/tun.rs
+++ b/talpid-core/src/split_tunnel/macos/tun.rs
@@ -22,9 +22,10 @@ use pnet_packet::{
use std::{
ffi::{c_uint, CStr},
io::{self, IoSlice, Write},
- net::{Ipv4Addr, Ipv6Addr},
+ net::{IpAddr, Ipv4Addr, Ipv6Addr},
};
use talpid_routing::RouteManagerHandle;
+use talpid_types::net::{ALLOWED_LAN_MULTICAST_NETS, ALLOWED_LAN_NETS};
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
sync::broadcast,
@@ -676,6 +677,10 @@ async fn handle_incoming_data_v4(
log::trace!("Dropping packet to VPN IP on default interface");
return;
}
+ if is_private_ip(IpAddr::from(ip.get_source())) {
+ // Drop packets from private IPs
+ return;
+ }
fix_ipv4_checksums(&mut ip, None, Some(vpn_addr));
@@ -698,6 +703,10 @@ async fn handle_incoming_data_v6(
log::trace!("Dropping packet to VPN IP on default interface");
return;
}
+ if is_private_ip(IpAddr::from(ip.get_source())) {
+ // Drop packets from private IPs
+ return;
+ }
fix_ipv6_checksums(&mut ip, None, Some(vpn_addr));
@@ -710,6 +719,13 @@ async fn handle_incoming_data_v6(
}
}
+fn is_private_ip(ip: IpAddr) -> bool {
+ ALLOWED_LAN_NETS
+ .iter()
+ .chain(ALLOWED_LAN_MULTICAST_NETS.iter())
+ .any(|net| net.contains(ip))
+}
+
// Recalculate L3 and L4 checksums. Silently fail on error
fn fix_ipv4_checksums(
ip: &mut MutableIpv4Packet<'_>,