瀏覽代碼

Make partial blocking per-user, use bridges immediately

Vecna 1 年之前
父節點
當前提交
fcbffdc53e
共有 1 個文件被更改,包括 104 次插入33 次删除
  1. 104 33
      src/user.rs

+ 104 - 33
src/user.rs

@@ -40,6 +40,13 @@ pub struct User {
 
     // How likely is this user to use bridges on a given day?
     prob_use_bridges: f64,
+
+    // If the censor implements partial blocking, is the user blocked?
+    in_censorship_range: bool,
+
+    // Track date the user joined and whether they're able to connect
+    pub join_date: u32,
+    pub able_to_connect: bool,
 }
 
 impl User {
@@ -51,29 +58,51 @@ impl User {
     ) -> Result<Self> {
         let cred = Self::get_new_credential(&config).await?.0;
 
-        // Probabilistically decide whether this user submits reports
-        let submits_reports = if is_censor {
-            false
+        // Decide how likely this user is to use bridges on a given day
+        // and whether they submit reports
+        let (prob_use_bridges, submits_reports) = if is_censor {
+            (0.0, false)
         } else {
-            event_happens(config.prob_user_submits_reports)
+            let mut rng = rand::thread_rng();
+            let prob_use_bridges = rng.gen_range(0.0..=1.0);
+            let submits_reports = event_happens(config.prob_user_submits_reports);
+            (prob_use_bridges, submits_reports)
         };
 
-        // Randomly determine how likely this user is to use bridges on
-        // a given day
-        let mut rng = rand::thread_rng();
-        let prob_use_bridges = rng.gen_range(0.0..=1.0);
+        let in_censorship_range = if config.censor_totality == Partial {
+            event_happens(config.censor_partial_blocking_percent)
+        } else {
+            true
+        };
 
-        // If the user cooperates with the censor, immediately tell the
-        // censor about all the bridges
-        if is_censor {
-            let (bucket, _reachcred) = get_bucket(&config.la_net, &cred).await?;
-            for bridgeline in bucket {
-                if bridgeline != BridgeLine::default() {
-                    if !bridges.contains_key(&bridgeline.get_hashed_fingerprint()) {
-                        let bridge = Bridge::from_bridge_line(&bridgeline);
-                        bridges.insert(bridgeline.get_hashed_fingerprint(), bridge);
-                    }
+        let mut able_to_connect = false;
+
+        // Immediately download and try to use our bridges, or report them to the censor.
+        let (bucket, _reachcred) = get_bucket(&config.la_net, &cred).await?;
+        for bridgeline in bucket {
+            if bridgeline != BridgeLine::default() {
+                if !bridges.contains_key(&bridgeline.get_hashed_fingerprint()) {
+                    let bridge = Bridge::from_bridge_line(&bridgeline);
+                    bridges.insert(bridgeline.get_hashed_fingerprint(), bridge);
+                }
+                let bridge = bridges
+                    .get_mut(&bridgeline.get_hashed_fingerprint())
+                    .unwrap();
+                if is_censor {
                     censor.learn_bridge(&bridgeline.get_hashed_fingerprint());
+                } else if Self::connect(in_censorship_range, config, bridge, censor) {
+                    able_to_connect = true;
+                } else if submits_reports {
+                    // New user only has one bridge, so no need
+                    // to collect the negative reports before
+                    // sending. Just send one now.
+                    let mut negative_reports = Vec::<NegativeReport>::new();
+                    negative_reports.push(NegativeReport::from_bridgeline(
+                        bridgeline,
+                        config.country.to_string(),
+                        BridgeDistributor::Lox,
+                    ));
+                    Self::send_negative_reports(&config, negative_reports).await?;
                 }
             }
         }
@@ -84,6 +113,9 @@ impl User {
             secondary_cred: None,
             submits_reports: submits_reports,
             prob_use_bridges: prob_use_bridges,
+            in_censorship_range,
+            join_date: get_date(),
+            able_to_connect,
         })
     }
 
@@ -139,20 +171,50 @@ impl User {
             (prob_use_bridges, submits_reports)
         };
 
-        // If the user cooperates with the censor, immediately tell the
-        // censor about all the bridges
-        if is_censor {
-            let (bucket, _reachcred) = get_bucket(&config.la_net, &self.primary_cred).await?;
-            for bridgeline in bucket {
-                if bridgeline != BridgeLine::default() {
-                    if !bridges.contains_key(&bridgeline.get_hashed_fingerprint()) {
-                        let bridge = Bridge::from_bridge_line(&bridgeline);
-                        bridges.insert(bridgeline.get_hashed_fingerprint(), bridge);
-                    }
+        let in_censorship_range = if config.censor_totality == Partial {
+            event_happens(config.censor_partial_blocking_percent)
+        } else {
+            true
+        };
+
+        let mut able_to_connect = false;
+
+        // Immediately download bucket and test bridges or give them to
+        // the censor
+        let mut negative_reports = Vec::<NegativeReport>::new();
+        let (bucket, _reachcred) = get_bucket(&config.la_net, &friend_cred).await?;
+        for bridgeline in bucket {
+            if bridgeline != BridgeLine::default() {
+                if !bridges.contains_key(&bridgeline.get_hashed_fingerprint()) {
+                    let bridge = Bridge::from_bridge_line(&bridgeline);
+                    bridges.insert(bridgeline.get_hashed_fingerprint(), bridge);
+                }
+                let bridge = bridges
+                    .get_mut(&bridgeline.get_hashed_fingerprint())
+                    .unwrap();
+                if is_censor {
                     censor.learn_bridge(&bridgeline.get_hashed_fingerprint());
+                } else if Self::connect(in_censorship_range, config, bridge, censor) {
+                    able_to_connect = true;
+                } else if submits_reports {
+                    negative_reports.push(NegativeReport::from_bridgeline(
+                        bridgeline,
+                        config.country.to_string(),
+                        BridgeDistributor::Lox,
+                    ));
                 }
             }
         }
+        // Submit reports if we have them
+        if negative_reports.len() > 0 {
+            Self::send_negative_reports(&config, negative_reports).await?;
+        }
+
+        let in_censorship_range = if config.censor_totality == Partial {
+            event_happens(config.censor_partial_blocking_percent)
+        } else {
+            true
+        };
 
         Ok(Self {
             is_censor,
@@ -160,17 +222,24 @@ impl User {
             secondary_cred: None,
             submits_reports: submits_reports,
             prob_use_bridges: prob_use_bridges,
+            in_censorship_range,
+            join_date: get_date(),
+            able_to_connect,
         })
     }
 
     // Attempt to "connect" to the bridge, returns true if successful.
     // Note that this does not involve making a real connection to a
     // real bridge.
-    pub fn connect(&self, config: &Config, bridge: &mut Bridge, censor: &Censor) -> bool {
+    pub fn connect(
+        in_censorship_range: bool,
+        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 == Partial && in_censorship_range
             {
                 // If censor tries to hide its censorship, record a
                 // false connection
@@ -327,7 +396,8 @@ impl User {
             for i in 0..bucket.len() {
                 // At level 0, we only have 1 bridge
                 if bucket[i] != BridgeLine::default() {
-                    if self.connect(
+                    if Self::connect(
+                        self.in_censorship_range,
                         &config,
                         bridges
                             .get_mut(&bucket[i].get_hashed_fingerprint())
@@ -374,7 +444,8 @@ impl User {
                             );
                         }
                         // Attempt to connect to second cred's bridge
-                        if self.connect(
+                        if Self::connect(
+                            self.in_censorship_range,
                             &config,
                             bridges
                                 .get_mut(&bridgeline.get_hashed_fingerprint())