summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--talpid-core/src/dns/macos.rs4
-rw-r--r--talpid-core/src/offline/macos.rs2
-rw-r--r--talpid-routing/src/debounce.rs1
-rw-r--r--talpid-routing/src/unix/macos/mod.rs8
-rw-r--r--talpid-routing/src/unix/macos/routing_socket.rs2
-rw-r--r--talpid-types/Cargo.toml1
-rw-r--r--talpid-types/src/error.rs56
8 files changed, 75 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ab0433f672..cf5dece12a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3744,6 +3744,7 @@ dependencies = [
"base64 0.13.1",
"ipnetwork",
"jnix",
+ "log",
"serde",
"thiserror",
"x25519-dalek",
diff --git a/talpid-core/src/dns/macos.rs b/talpid-core/src/dns/macos.rs
index c68165737f..82deb1bd67 100644
--- a/talpid-core/src/dns/macos.rs
+++ b/talpid-core/src/dns/macos.rs
@@ -88,6 +88,8 @@ impl State {
interface: &str,
servers: &[IpAddr],
) -> Result<()> {
+ talpid_types::detect_flood!();
+
let servers: Vec<DnsServer> = servers.iter().map(|ip| ip.to_string()).collect();
let new_settings = DnsSettings::from_server_addresses(&servers, interface.to_string());
match &self.dns_settings {
@@ -115,6 +117,8 @@ impl State {
}
fn on_changed_keys(&mut self, store: SCDynamicStore, changed_keys: CFArray<CFString>) {
+ talpid_types::detect_flood!();
+
if let Some(expected_settings) = &self.dns_settings {
for path in &changed_keys {
let should_set_dns = match DnsSettings::load(&store, path.clone()).ok() {
diff --git a/talpid-core/src/offline/macos.rs b/talpid-core/src/offline/macos.rs
index 51596f77c2..2813dc4211 100644
--- a/talpid-core/src/offline/macos.rs
+++ b/talpid-core/src/offline/macos.rs
@@ -96,6 +96,8 @@ pub async fn spawn_monitor(
let mut route_listener = route_listener.fuse();
loop {
+ talpid_types::detect_flood!();
+
select! {
_ = timeout => {
// Update shared state
diff --git a/talpid-routing/src/debounce.rs b/talpid-routing/src/debounce.rs
index 2463b2c429..fe51447624 100644
--- a/talpid-routing/src/debounce.rs
+++ b/talpid-routing/src/debounce.rs
@@ -99,6 +99,7 @@ impl BurstGuard {
/// Asynchronously trigger burst
pub fn trigger(&self) {
+ talpid_types::detect_flood!();
self.trigger_with_period(self.buffer_period)
}
diff --git a/talpid-routing/src/unix/macos/mod.rs b/talpid-routing/src/unix/macos/mod.rs
index 7a1c120621..448a87427c 100644
--- a/talpid-routing/src/unix/macos/mod.rs
+++ b/talpid-routing/src/unix/macos/mod.rs
@@ -158,12 +158,16 @@ impl RouteManagerImpl {
let mut completion_tx = None;
loop {
+ talpid_types::detect_flood!();
+
futures::select_biased! {
route_message = self.routing_table.next_message().fuse() => {
self.handle_route_message(route_message);
}
_ = self.check_default_routes_restored.next() => {
+ talpid_types::detect_flood!();
+
if self.check_default_routes_restored.is_terminated() {
continue;
}
@@ -328,6 +332,8 @@ impl RouteManagerImpl {
&mut self,
message: std::result::Result<RouteSocketMessage, watch::Error>,
) {
+ talpid_types::detect_flood!();
+
match message {
Ok(RouteSocketMessage::DeleteRoute(route)) => {
// Forget about applied route, if relevant
@@ -380,6 +386,8 @@ impl RouteManagerImpl {
/// server. The gateway of the relay route is set to the first interface in the network
/// service order that has a working ifscoped default route.
async fn refresh_routes(&mut self) -> Result<()> {
+ talpid_types::detect_flood!();
+
self.update_best_default_route(interface::Family::V4)?;
self.update_best_default_route(interface::Family::V6)?;
diff --git a/talpid-routing/src/unix/macos/routing_socket.rs b/talpid-routing/src/unix/macos/routing_socket.rs
index 835e7d6edc..ab02f1cff2 100644
--- a/talpid-routing/src/unix/macos/routing_socket.rs
+++ b/talpid-routing/src/unix/macos/routing_socket.rs
@@ -87,6 +87,8 @@ impl RoutingSocket {
pub async fn wait_for_response(&mut self, response_num: i32) -> Result<Vec<u8>> {
loop {
+ talpid_types::detect_flood!();
+
let mut buffer = vec![0u8; 2048];
// do not truncate the buffer - trailing empty bytes won't be written but will be
// assumed in the data format.
diff --git a/talpid-types/Cargo.toml b/talpid-types/Cargo.toml
index c44001b4cd..7582387b68 100644
--- a/talpid-types/Cargo.toml
+++ b/talpid-types/Cargo.toml
@@ -17,6 +17,7 @@ base64 = "0.13"
x25519-dalek = { version = "2.0.1", features = ["static_secrets", "zeroize", "getrandom"] }
thiserror = { workspace = true }
zeroize = "1.5.7"
+log = { workspace = true }
[target.'cfg(target_os = "android")'.dependencies]
jnix = { version = "0.5.1", features = ["derive"] }
diff --git a/talpid-types/src/error.rs b/talpid-types/src/error.rs
index 77f0664375..e4471eff29 100644
--- a/talpid-types/src/error.rs
+++ b/talpid-types/src/error.rs
@@ -68,3 +68,59 @@ macro_rules! win32_err {
}
}};
}
+
+pub mod flood {
+ #[doc(hidden)]
+ pub use log;
+
+ use std::time::{Duration, Instant};
+
+ const CALLS_INTERVAL: Duration = Duration::from_secs(5);
+ const CALLS_THRESHOLD: usize = 1000;
+
+ /// Log when a line is hit unusually frequently, that is, over `CALLS_THRESHOLD` times within a
+ /// period of `CALLS_INTERVAL`.
+ #[macro_export]
+ macro_rules! detect_flood {
+ () => {{
+ static FLOOD: ::std::sync::Mutex<$crate::flood::DetectFlood> =
+ ::std::sync::Mutex::new($crate::flood::DetectFlood::new());
+ if FLOOD.lock().unwrap().bump() {
+ $crate::flood::log::warn!(
+ "Flood: {}, line {}, col {}",
+ file!(),
+ line!(),
+ column!()
+ );
+ }
+ }};
+ }
+
+ /// Used to detect code that is running too frequently
+ pub struct DetectFlood {
+ last_clear: Option<Instant>,
+ counter: usize,
+ }
+
+ impl DetectFlood {
+ pub const fn new() -> Self {
+ DetectFlood {
+ last_clear: None,
+ counter: 0,
+ }
+ }
+
+ pub fn bump(&mut self) -> bool {
+ let now = Instant::now();
+ let last_clear = self.last_clear.get_or_insert(now);
+ if now.saturating_duration_since(*last_clear) >= CALLS_INTERVAL {
+ self.last_clear = Some(now);
+ self.counter = 0;
+ false
+ } else {
+ self.counter = self.counter.saturating_add(1);
+ self.counter == CALLS_THRESHOLD
+ }
+ }
+ }
+}