diff --git a/src/lib.rs b/src/lib.rs index a03e5d7..f8f6bbd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -837,6 +837,71 @@ pub fn guess_blockages( blockages } +/// Verify bridges suspected of being blocked, return only the ones that are +/// actually blocked +pub async fn verify_blockages( + verify_blockages_url: &str, + suspected_blockages: HashMap<[u8; 20], HashSet>, +) -> HashMap<[u8; 20], HashSet> { + // If we don't have a resource for checking if bridges are blocked, assume + // that Troll Patrol guessed correctly + if verify_blockages_url.is_empty() { + return suspected_blockages; + } + + // Convert map keys from [u8; 20] to 40-character hex strings + let mut suspected_blockages_str = HashMap::>::new(); + for (fingerprint, countries) in &suspected_blockages { + let fpr_string = array_bytes::bytes2hex("", fingerprint); + if !countries.is_empty() { + suspected_blockages_str.insert(fpr_string, countries.clone()); + } + } + + if !suspected_blockages_str.is_empty() { + // Send suspected blockages to verification endpoint for verification + let client = Client::new(); + let req = Request::builder() + .method(Method::POST) + .uri(verify_blockages_url) + .body(Body::from( + serde_json::to_string(&suspected_blockages_str).unwrap(), + )) + .unwrap(); + let resp = client.request(req).await.unwrap(); + let buf = hyper::body::to_bytes(resp).await.unwrap(); + let resp_str = String::from_utf8(buf.to_vec()).unwrap(); + + // Deserialize map + let blockages_str: HashMap> = match serde_json::from_str(&resp_str) + { + Ok(v) => v, + Err(e) => { + eprintln!( + "Failed to deserialize response from verification endpoint: {:?}", + e + ); + HashMap::>::new() + } + }; + + // Convert map so it uses [u8; 20]s as keys again + let mut blockages = HashMap::<[u8; 20], HashSet>::new(); + for (fingerprint, countries) in blockages_str { + if let Ok(fpr) = array_bytes::hex2array(fingerprint) { + if !countries.is_empty() { + blockages.insert(fpr, countries); + } + } + } + + // Return map of confirmed blockages + blockages + } else { + suspected_blockages + } +} + /// Commit blocked bridges to database pub fn commit_blockages(db: &Db, blockages: &HashMap<[u8; 20], HashSet>) { // For each bridge:, mark the bridge as blocked in each country diff --git a/src/main.rs b/src/main.rs index c517ef5..9e9d950 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,6 +51,7 @@ pub struct Config { // map of distributor name to IP:port to contact it pub distributors: BTreeMap, extra_infos_base_url: String, + verify_blockages_url: String, // confidence required to consider a bridge blocked confidence: f64, @@ -92,6 +93,7 @@ async fn update_daily_info( db: &Db, distributors: &BTreeMap, extra_infos_base_url: &str, + verify_blockages_url: &str, confidence: f64, max_threshold: u32, scaling_factor: f64, @@ -109,7 +111,10 @@ async fn update_daily_info( min_historical_days, max_historical_days, ); - // TODO: Verify the new blockages + + // This implementation will vary based on scanning infrastructure + let new_blockages = verify_blockages(verify_blockages_url, new_blockages).await; + commit_blockages(db, &new_blockages); report_blockages(distributors, new_blockages.clone()).await; @@ -132,6 +137,7 @@ async fn create_context_manager( db_config: DbConfig, distributors: BTreeMap, extra_infos_base_url: &str, + verify_blockages_url: &str, confidence: f64, max_threshold: u32, scaling_factor: f64, @@ -141,7 +147,7 @@ async fn create_context_manager( mut kill: broadcast::Receiver<()>, ) { tokio::select! { - create_context = context_manager(db_config, distributors, extra_infos_base_url, confidence, max_threshold, scaling_factor, min_historical_days, max_historical_days, context_rx) => create_context, + create_context = context_manager(db_config, distributors, extra_infos_base_url, verify_blockages_url, confidence, max_threshold, scaling_factor, min_historical_days, max_historical_days, context_rx) => create_context, _ = kill.recv() => {println!("Shut down manager");}, } } @@ -150,6 +156,7 @@ async fn context_manager( db_config: DbConfig, distributors: BTreeMap, extra_infos_base_url: &str, + verify_blockages_url: &str, confidence: f64, max_threshold: u32, scaling_factor: f64, @@ -202,6 +209,7 @@ async fn context_manager( &db, &distributors, extra_infos_base_url, + verify_blockages_url, confidence, max_threshold, scaling_factor, @@ -296,6 +304,7 @@ async fn main() { config.db, config.distributors, &config.extra_infos_base_url, + &config.verify_blockages_url, config.confidence, config.max_threshold, config.scaling_factor,