From c3b19081202c7e2610a671d28daab3dea59ea2a8 Mon Sep 17 00:00:00 2001 From: Vecna Date: Tue, 4 Jun 2024 09:45:44 -0400 Subject: [PATCH] Add probability of user treating throttling as interference --- src/bin/simulation.rs | 2 ++ src/simulation/censor.rs | 41 +++++++++++++++--------- src/simulation/config.rs | 1 + src/simulation/user.rs | 68 ++++++++++++++++++++++++++++------------ 4 files changed, 78 insertions(+), 34 deletions(-) diff --git a/src/bin/simulation.rs b/src/bin/simulation.rs index 153f440..dac46ec 100644 --- a/src/bin/simulation.rs +++ b/src/bin/simulation.rs @@ -61,6 +61,7 @@ pub struct Config { pub prob_user_invites_friend: f64, pub prob_user_is_censor: f64, pub prob_user_submits_reports: f64, + pub prob_user_treats_throttling_as_blocking: f64, } #[tokio::main] @@ -105,6 +106,7 @@ pub async fn main() { prob_user_invites_friend: config.prob_user_invites_friend, prob_user_is_censor: config.prob_user_is_censor, prob_user_submits_reports: config.prob_user_submits_reports, + prob_user_treats_throttling_as_blocking: config.prob_user_treats_throttling_as_blocking, }; let mut rng = rand::thread_rng(); diff --git a/src/simulation/censor.rs b/src/simulation/censor.rs index 1154ead..643d884 100644 --- a/src/simulation/censor.rs +++ b/src/simulation/censor.rs @@ -94,6 +94,31 @@ impl Censor { } } + // Censor sends a positive report for the given bridge. Returns true + // if successful, false otherwise. + pub async fn send_positive_report(&self, config: &Config, fingerprint: &[u8; 20]) -> bool { + // If we don't have an appropriate Lox credential, we can't send + // a report. Return false. + if !self.has_lox_cred(fingerprint) { + return false; + } + + let (cred, _) = &self.lox_credentials.get(fingerprint).unwrap(); + let pr = PositiveReport::from_lox_credential( + *fingerprint, + None, + cred, + get_lox_pub(&config.la_pubkeys), + config.country.clone(), + ) + .unwrap(); + config + .tp_net + .request("/positivereport".to_string(), pr.to_json().into_bytes()) + .await; + true + } + // Make a bunch of connections and submit positive reports if possible async fn flood(&self, config: &Config, bridges: &mut HashMap<[u8; 20], Bridge>) { // Only do this if Flooding censor @@ -115,8 +140,7 @@ impl Censor { // If we have a lv3+ credential, submit a bunch of // positive reports if self.has_lox_cred(fingerprint) { - let lox_pub = get_lox_pub(&config.la_pubkeys); - let (cred, cred_count) = + let (_cred, cred_count) = &self.lox_credentials.get(&bridge.fingerprint).unwrap(); let num_prs = if config.one_positive_report_per_cred { *cred_count @@ -124,18 +148,7 @@ impl Censor { rng.gen_range(1000..30000) }; for _ in 0..num_prs { - let pr = PositiveReport::from_lox_credential( - bridge.fingerprint, - None, - cred, - lox_pub, - config.country.clone(), - ) - .unwrap(); - config - .tp_net - .request("/positivereport".to_string(), pr.to_json().into_bytes()) - .await; + self.send_positive_report(config, &bridge.fingerprint).await; } } } diff --git a/src/simulation/config.rs b/src/simulation/config.rs index 2b94f93..d48c5fc 100644 --- a/src/simulation/config.rs +++ b/src/simulation/config.rs @@ -23,4 +23,5 @@ pub struct Config { pub prob_user_invites_friend: f64, pub prob_user_is_censor: f64, pub prob_user_submits_reports: f64, + pub prob_user_treats_throttling_as_blocking: f64, } diff --git a/src/simulation/user.rs b/src/simulation/user.rs index 7cc4345..0d19038 100644 --- a/src/simulation/user.rs +++ b/src/simulation/user.rs @@ -156,23 +156,45 @@ impl User { }) } - // Attempt to "connect" to the bridge, returns true if successful - pub fn connect(&self, config: &Config, bridge: &mut Bridge, censor: &Censor) -> bool { + // Attempt to "connect" to the bridge, returns true if successful. + // Note that this does not involve making a real connection to a + // real bridge. The function is async because the *censor* might + // submit a positive report during this function. + pub async fn connect(&self, config: &Config, bridge: &mut Bridge, censor: &Censor) -> bool { if censor.blocks_bridge(config, &bridge.fingerprint) { if config.censor_totality == Full || config.censor_totality == Partial && event_happens(censor.partial_blocking_percent) - || config.censor_totality == Throttling { - // If censor tries to hide its censorship or - // throttles rather than actually blocking, record a + // If censor tries to hide its censorship, record a // false connection - if config.censor_hides == Hiding || config.censor_totality == Throttling { + if config.censor_hides == Hiding { bridge.connect_total(); } // Return false because the connection failed return false; + } else if config.censor_totality == Throttling { + // With some probability, the user connects but gives up + // because there is too much interference. In this case, + // a real connection occurs, but we treat it like a + // false connection from the censor. + if event_happens(config.prob_user_treats_throttling_as_blocking) { + bridge.connect_total(); + + // A Hiding censor does not make an additional + // connection here, but it will make a false + // positive report if possible. + if config.censor_hides == Hiding && censor.has_lox_cred(&bridge.fingerprint) { + censor + .send_positive_report(config, &bridge.fingerprint) + .await; + } + + // Return false because there was interference + // detected in the connection + return false; + } } } @@ -291,13 +313,16 @@ impl User { for i in 0..bucket.len() { // At level 0, we only have 1 bridge if bucket[i] != BridgeLine::default() { - if self.connect( - &config, - bridges - .get_mut(&bucket[i].get_hashed_fingerprint()) - .unwrap(), - &censor, - ) { + if self + .connect( + &config, + bridges + .get_mut(&bucket[i].get_hashed_fingerprint()) + .unwrap(), + &censor, + ) + .await + { succeeded.push(bucket[i]); } else { failed.push(bucket[i]); @@ -338,13 +363,16 @@ impl User { ); } // Attempt to connect to second cred's bridge - if self.connect( - &config, - bridges - .get_mut(&bridgeline.get_hashed_fingerprint()) - .unwrap(), - censor, - ) { + if self + .connect( + &config, + bridges + .get_mut(&bridgeline.get_hashed_fingerprint()) + .unwrap(), + censor, + ) + .await + { succeeded.push(bridgeline); if second_reachcred.is_some() && eligible_for_trust_promotion(&config.la_net, &second_cred).await