Compare commits

..

No commits in common. "498d6b4cee1a43588308aca97c2cf49a16df7394" and "9495c8cbdadbc6a21f719ee5ba8531b92b0d1e6f" have entirely different histories.

6 changed files with 68 additions and 119 deletions

View File

@ -7,7 +7,6 @@ edition = "2021"
[dependencies] [dependencies]
aes-gcm = "0.10" aes-gcm = "0.10"
anyhow = "1.0"
array-bytes = "6.2.0" array-bytes = "6.2.0"
bincode = "1" bincode = "1"
chrono = "0.4" chrono = "0.4"

View File

@ -44,7 +44,7 @@ pub struct Config {
pub la_test_port: u16, pub la_test_port: u16,
pub tp_port: u16, pub tp_port: u16,
pub tp_test_port: u16, pub tp_test_port: u16,
pub censor_secrecy: censor::Secrecy, pub censor_hides: censor::Hides,
pub censor_speed: censor::Speed, pub censor_speed: censor::Speed,
pub censor_event_duration: u32, pub censor_event_duration: u32,
pub censor_totality: censor::Totality, pub censor_totality: censor::Totality,
@ -96,7 +96,7 @@ pub async fn main() {
la_pubkeys, la_pubkeys,
la_net, la_net,
tp_net, tp_net,
censor_secrecy: config.censor_secrecy, censor_hides: config.censor_hides,
censor_speed: config.censor_speed, censor_speed: config.censor_speed,
censor_event_duration: config.censor_event_duration, censor_event_duration: config.censor_event_duration,
censor_totality: config.censor_totality, censor_totality: config.censor_totality,
@ -141,8 +141,7 @@ pub async fn main() {
.unwrap() .unwrap()
.into(), .into(),
) )
.await .await;
.unwrap();
// Advance simulated time // Advance simulated time
set_simulated_date(get_date() + UNTRUSTED_INTERVAL); set_simulated_date(get_date() + UNTRUSTED_INTERVAL);
@ -177,8 +176,7 @@ pub async fn main() {
.unwrap() .unwrap()
.into(), .into(),
) )
.await .await;
.unwrap();
// Advance simulated time // Advance simulated time
set_simulated_date(get_date() + LEVEL_INTERVAL[i]); set_simulated_date(get_date() + LEVEL_INTERVAL[i]);
@ -209,8 +207,7 @@ pub async fn main() {
"/advancedays".to_string(), "/advancedays".to_string(),
serde_json::to_string(&(1 as u16)).unwrap().into(), serde_json::to_string(&(1 as u16)).unwrap().into(),
) )
.await .await;
.unwrap();
// Advance simulated time to tomorrow // Advance simulated time to tomorrow
increment_simulated_date(); increment_simulated_date();
@ -369,14 +366,10 @@ pub async fn main() {
"/add".to_string(), "/add".to_string(),
serde_json::to_string(&new_extra_infos).unwrap().into(), serde_json::to_string(&new_extra_infos).unwrap().into(),
) )
.await .await;
.unwrap();
// TROLL PATROL TASKS // TROLL PATROL TASKS
let new_blockages_resp = tp_net_test let new_blockages_resp = tp_net_test.request("/update".to_string(), vec![]).await;
.request("/update".to_string(), vec![])
.await
.unwrap();
let new_blockages: HashMap<String, HashSet<String>> = let new_blockages: HashMap<String, HashSet<String>> =
serde_json::from_slice(&new_blockages_resp).unwrap(); serde_json::from_slice(&new_blockages_resp).unwrap();
@ -422,8 +415,7 @@ pub async fn main() {
"/advancedays".to_string(), "/advancedays".to_string(),
serde_json::to_string(&(1 as u16)).unwrap().into(), serde_json::to_string(&(1 as u16)).unwrap().into(),
) )
.await .await;
.unwrap();
// SIMULATION TASKS // SIMULATION TASKS

View File

@ -26,8 +26,8 @@ pub struct Bridge {
// bridge (for identifying stage three) // bridge (for identifying stage three)
pub first_positive_report: u32, pub first_positive_report: u32,
pub real_connections: u32, real_connections: u32,
pub total_connections: u32, total_connections: u32,
} }
impl Bridge { impl Bridge {

View File

@ -8,10 +8,7 @@ use lox_cli::{get_lox_pub, networking::Networking};
use lox_library::{cred::Lox, scalar_u32}; use lox_library::{cred::Lox, scalar_u32};
use rand::Rng; use rand::Rng;
use serde::Deserialize; use serde::Deserialize;
use std::{ use std::collections::{HashMap, HashSet};
cmp::min,
collections::{HashMap, HashSet},
};
pub struct Censor { pub struct Censor {
pub known_bridges: HashSet<[u8; 20]>, pub known_bridges: HashSet<[u8; 20]>,
@ -115,22 +112,17 @@ impl Censor {
config.country.clone(), config.country.clone(),
) )
.unwrap(); .unwrap();
if config config
.tp_net .tp_net
.request("/positivereport".to_string(), pr.to_json().into_bytes()) .request("/positivereport".to_string(), pr.to_json().into_bytes())
.await .await;
.is_err()
{
// failed to send positive report
return false;
}
true true
} }
// Make a bunch of connections and submit positive reports if possible // Make a bunch of connections and submit positive reports if possible
async fn flood(&self, config: &Config, bridges: &mut HashMap<[u8; 20], Bridge>) { async fn flood(&self, config: &Config, bridges: &mut HashMap<[u8; 20], Bridge>) {
// Only do this if Flooding censor // Only do this if Flooding censor
if config.censor_secrecy == Secrecy::Flooding { if config.censor_hides == Hides::Flooding {
for fingerprint in &self.known_bridges { for fingerprint in &self.known_bridges {
// Only do this if we're blocking the bridge // Only do this if we're blocking the bridge
if config.censor_speed == Speed::Fast if config.censor_speed == Speed::Fast
@ -164,38 +156,6 @@ impl Censor {
} }
} }
// Send one positive report per connection we blocked
async fn send_positive_reports(
&self,
config: &Config,
bridges: &mut HashMap<[u8; 20], Bridge>,
) {
// Only do this if Hiding censor. Flooding censors should use
// flood() instead.
if config.censor_secrecy == Secrecy::Hiding {
for fingerprint in &self.known_bridges {
// Only do this if we're blocking the bridge
if self.blocks_bridge(config, fingerprint) && self.has_lox_cred(fingerprint) {
let bridge = bridges.get_mut(fingerprint).unwrap();
// We may be restricted to one positive report per
// credential
let num_reports_to_send = if config.one_positive_report_per_cred {
min(
bridge.total_connections - bridge.real_connections,
self.lox_credentials.get(fingerprint).unwrap().1,
)
} else {
bridge.total_connections - bridge.real_connections
};
for _ in 0..num_reports_to_send {
self.send_positive_report(config, fingerprint).await;
}
}
}
}
}
fn recompute_delay(&mut self, config: &Config) { fn recompute_delay(&mut self, config: &Config) {
// Only do this if Random censor // Only do this if Random censor
if config.censor_speed == Speed::Random if config.censor_speed == Speed::Random
@ -215,14 +175,10 @@ impl Censor {
config: &Config, config: &Config,
bridges: &mut HashMap<[u8; 20], Bridge>, bridges: &mut HashMap<[u8; 20], Bridge>,
) { ) {
if config.censor_secrecy == Secrecy::Flooding if config.censor_hides == Hides::Flooding
&& !(config.censor_speed == Speed::Random && self.delay_date <= get_date()) && !(config.censor_speed == Speed::Random && self.delay_date <= get_date())
{ {
self.flood(config, bridges).await; self.flood(config, bridges).await;
} else if config.censor_secrecy == Secrecy::Hiding
&& !(config.censor_speed == Speed::Random && self.delay_date <= get_date())
{
self.send_positive_reports(config, bridges).await;
} }
self.recompute_delay(config); self.recompute_delay(config);
@ -237,7 +193,7 @@ pub enum Speed {
} }
#[derive(Clone, Copy, Debug, Deserialize, PartialEq)] #[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
pub enum Secrecy { pub enum Hides {
Overt, Overt,
Hiding, Hiding,
Flooding, Flooding,

View File

@ -8,7 +8,7 @@ pub struct Config {
pub la_net: HyperNet, pub la_net: HyperNet,
pub tp_net: HyperNet, pub tp_net: HyperNet,
// Define censor behavior // Define censor behavior
pub censor_secrecy: censor::Secrecy, pub censor_hides: censor::Hides,
pub censor_speed: censor::Speed, pub censor_speed: censor::Speed,
pub censor_event_duration: u32, pub censor_event_duration: u32,
pub censor_totality: censor::Totality, pub censor_totality: censor::Totality,

View File

@ -6,17 +6,17 @@ use crate::{
positive_report::PositiveReport, positive_report::PositiveReport,
simulation::{ simulation::{
bridge::Bridge, bridge::Bridge,
censor::{Censor, Secrecy::*, Totality::*}, censor::{Censor, Hides::*, Totality::*},
config::Config, config::Config,
}, },
BridgeDistributor, BridgeDistributor,
}; };
use anyhow::{anyhow, Result};
use lox_cli::{networking::*, *}; use lox_cli::{networking::*, *};
use lox_library::{ use lox_library::{
bridge_table::BridgeLine, cred::Lox, proto::check_blockage::MIN_TRUST_LEVEL, scalar_u32, bridge_table::BridgeLine, cred::Lox, proto::check_blockage::MIN_TRUST_LEVEL, scalar_u32,
}; };
use rand::Rng; use rand::Rng;
use serde_json::error::Error;
use std::{cmp::min, collections::HashMap}; use std::{cmp::min, collections::HashMap};
use x25519_dalek::PublicKey; use x25519_dalek::PublicKey;
@ -45,7 +45,7 @@ pub struct User {
} }
impl User { impl User {
pub async fn new(config: &Config, is_censor: bool) -> Result<Self> { pub async fn new(config: &Config, is_censor: bool) -> Result<Self, Error> {
let cred = get_lox_credential( let cred = get_lox_credential(
&config.la_net, &config.la_net,
&get_open_invitation(&config.la_net).await?, &get_open_invitation(&config.la_net).await?,
@ -75,7 +75,7 @@ impl User {
}) })
} }
pub async fn trusted_user(config: &Config) -> Result<Self> { pub async fn trusted_user(config: &Config) -> Result<Self, Error> {
let cred = get_lox_credential( let cred = get_lox_credential(
&config.la_net, &config.la_net,
&get_open_invitation(&config.la_net).await?, &get_open_invitation(&config.la_net).await?,
@ -98,7 +98,7 @@ impl User {
config: &Config, config: &Config,
censor: &mut Censor, censor: &mut Censor,
invited_user_is_censor: bool, invited_user_is_censor: bool,
) -> Result<Self> { ) -> Result<Self, Error> {
let etable = get_reachability_credential(&config.la_net).await?; let etable = get_reachability_credential(&config.la_net).await?;
let (new_cred, invite) = issue_invite( let (new_cred, invite) = issue_invite(
&config.la_net, &config.la_net,
@ -157,7 +157,7 @@ impl User {
// Note that this does not involve making a real connection to a // Note that this does not involve making a real connection to a
// real bridge. The function is async because the *censor* might // real bridge. The function is async because the *censor* might
// submit a positive report during this function. // submit a positive report during this function.
pub fn connect(&self, config: &Config, bridge: &mut Bridge, censor: &Censor) -> bool { pub async fn connect(&self, config: &Config, bridge: &mut Bridge, censor: &Censor) -> bool {
if censor.blocks_bridge(config, &bridge.fingerprint) { if censor.blocks_bridge(config, &bridge.fingerprint) {
if config.censor_totality == Full if config.censor_totality == Full
|| config.censor_totality == Partial || config.censor_totality == Partial
@ -165,7 +165,7 @@ impl User {
{ {
// If censor tries to hide its censorship, record a // If censor tries to hide its censorship, record a
// false connection // false connection
if config.censor_secrecy == Hiding { if config.censor_hides == Hiding {
bridge.connect_total(); bridge.connect_total();
} }
@ -179,6 +179,15 @@ impl User {
if event_happens(config.prob_user_treats_throttling_as_blocking) { if event_happens(config.prob_user_treats_throttling_as_blocking) {
bridge.connect_total(); 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 // Return false because there was interference
// detected in the connection // detected in the connection
return false; return false;
@ -196,7 +205,7 @@ impl User {
true true
} }
pub async fn get_new_credential(config: &Config) -> Result<(Lox, BridgeLine)> { pub async fn get_new_credential(config: &Config) -> Result<(Lox, BridgeLine), Error> {
get_lox_credential( get_lox_credential(
&config.la_net, &config.la_net,
&get_open_invitation(&config.la_net).await?, &get_open_invitation(&config.la_net).await?,
@ -205,10 +214,7 @@ impl User {
.await .await
} }
pub async fn send_negative_reports( pub async fn send_negative_reports(config: &Config, reports: Vec<NegativeReport>) {
config: &Config,
reports: Vec<NegativeReport>,
) -> Result<()> {
let date = get_date(); let date = get_date();
let pubkey = serde_json::from_slice::<Option<PublicKey>>( let pubkey = serde_json::from_slice::<Option<PublicKey>>(
&config &config
@ -217,8 +223,9 @@ impl User {
"/nrkey".to_string(), "/nrkey".to_string(),
serde_json::to_string(&date).unwrap().into(), serde_json::to_string(&date).unwrap().into(),
) )
.await?, .await,
)? )
.unwrap()
.unwrap(); .unwrap();
for report in reports { for report in reports {
config config
@ -227,22 +234,17 @@ impl User {
"/negativereport".to_string(), "/negativereport".to_string(),
bincode::serialize(&report.encrypt(&pubkey)).unwrap(), bincode::serialize(&report.encrypt(&pubkey)).unwrap(),
) )
.await?; .await;
} }
Ok(())
} }
pub async fn send_positive_reports( pub async fn send_positive_reports(config: &Config, reports: Vec<PositiveReport>) {
config: &Config,
reports: Vec<PositiveReport>,
) -> Result<()> {
for report in reports { for report in reports {
config config
.tp_net .tp_net
.request("/positivereport".to_string(), report.to_json().into_bytes()) .request("/positivereport".to_string(), report.to_json().into_bytes())
.await?; .await;
} }
Ok(())
} }
pub async fn daily_tasks( pub async fn daily_tasks(
@ -252,7 +254,7 @@ impl User {
num_censor_invites: u32, num_censor_invites: u32,
bridges: &mut HashMap<[u8; 20], Bridge>, bridges: &mut HashMap<[u8; 20], Bridge>,
censor: &mut Censor, censor: &mut Censor,
) -> Result<Vec<User>> { ) -> Result<Vec<User>, Error> {
if self.is_censor { if self.is_censor {
self.daily_tasks_censor(config, bridges, censor).await self.daily_tasks_censor(config, bridges, censor).await
} else { } else {
@ -278,17 +280,14 @@ impl User {
num_censor_invites: u32, num_censor_invites: u32,
bridges: &mut HashMap<[u8; 20], Bridge>, bridges: &mut HashMap<[u8; 20], Bridge>,
censor: &mut Censor, censor: &mut Censor,
) -> Result<Vec<User>> { ) -> Result<Vec<User>, Error> {
// Probabilistically decide if the user should use bridges today // Probabilistically decide if the user should use bridges today
if event_happens(self.prob_use_bridges) { if event_happens(self.prob_use_bridges) {
// Download bucket to see if bridge is still reachable. (We // Download bucket to see if bridge is still reachable. (We
// assume that this step can be done even if the user can't // assume that this step can be done even if the user can't
// actually talk to the LA.) // actually talk to the LA.)
let (bucket, reachcred) = get_bucket(&config.la_net, &self.primary_cred).await?; let (bucket, reachcred) = get_bucket(&config.la_net, &self.primary_cred).await?;
let level = match scalar_u32(&self.primary_cred.trust_level) { let level = scalar_u32(&self.primary_cred.trust_level).unwrap();
Some(v) => v,
None => return Err(anyhow!("Failed to get trust level from credential")),
};
// Make sure each bridge in bucket is in the global bridges set // Make sure each bridge in bucket is in the global bridges set
for bridgeline in bucket { for bridgeline in bucket {
@ -319,13 +318,16 @@ impl User {
for i in 0..bucket.len() { for i in 0..bucket.len() {
// At level 0, we only have 1 bridge // At level 0, we only have 1 bridge
if bucket[i] != BridgeLine::default() { if bucket[i] != BridgeLine::default() {
if self.connect( if self
&config, .connect(
bridges &config,
.get_mut(&bucket[i].get_hashed_fingerprint()) bridges
.unwrap(), .get_mut(&bucket[i].get_hashed_fingerprint())
&censor, .unwrap(),
) { &censor,
)
.await
{
succeeded.push(bucket[i]); succeeded.push(bucket[i]);
} else { } else {
failed.push(bucket[i]); failed.push(bucket[i]);
@ -366,13 +368,16 @@ impl User {
); );
} }
// Attempt to connect to second cred's bridge // Attempt to connect to second cred's bridge
if self.connect( if self
&config, .connect(
bridges &config,
.get_mut(&bridgeline.get_hashed_fingerprint()) bridges
.unwrap(), .get_mut(&bridgeline.get_hashed_fingerprint())
censor, .unwrap(),
) { censor,
)
.await
{
succeeded.push(bridgeline); succeeded.push(bridgeline);
if second_reachcred.is_some() if second_reachcred.is_some()
&& eligible_for_trust_promotion(&config.la_net, &second_cred).await && eligible_for_trust_promotion(&config.la_net, &second_cred).await
@ -501,17 +506,14 @@ impl User {
} }
if negative_reports.len() > 0 { if negative_reports.len() > 0 {
Self::send_negative_reports(&config, negative_reports).await?; Self::send_negative_reports(&config, negative_reports).await;
} }
if positive_reports.len() > 0 { if positive_reports.len() > 0 {
Self::send_positive_reports(&config, positive_reports).await?; Self::send_positive_reports(&config, positive_reports).await;
} }
// Invite friends if applicable // Invite friends if applicable
let invitations = match scalar_u32(&self.primary_cred.invites_remaining) { let invitations = scalar_u32(&self.primary_cred.invites_remaining).unwrap();
Some(v) => v,
None => 0, // This is probably an error case that should not happen
};
let mut new_friends = Vec::<User>::new(); let mut new_friends = Vec::<User>::new();
for _i in 0..min(invitations, num_users_requesting_invites) { for _i in 0..min(invitations, num_users_requesting_invites) {
if event_happens(config.prob_user_invites_friend) { if event_happens(config.prob_user_invites_friend) {
@ -559,7 +561,7 @@ impl User {
config: &Config, config: &Config,
bridges: &mut HashMap<[u8; 20], Bridge>, bridges: &mut HashMap<[u8; 20], Bridge>,
censor: &mut Censor, censor: &mut Censor,
) -> Result<Vec<User>> { ) -> Result<Vec<User>, Error> {
// Download bucket to see if bridge is still reachable and if we // Download bucket to see if bridge is still reachable and if we
// have any new bridges // have any new bridges
let (bucket, reachcred) = get_bucket(&config.la_net, &self.primary_cred).await?; let (bucket, reachcred) = get_bucket(&config.la_net, &self.primary_cred).await?;