Compare commits

...

2 Commits

Author SHA1 Message Date
Vecna 498d6b4cee Change Hides to Secrecy, have censor submit all false reports at end
If the censor submits a report each time it blocks a connection, this number may exceed the number of Lox credentials the censor can actually use to submit these reports. This is an issue if we restrict these reports to one per credential.
2024-06-08 15:52:35 -04:00
Vecna bc834c329d Better error handling, update for lox_cli 2024-06-08 15:27:22 -04:00
6 changed files with 119 additions and 68 deletions

View File

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

View File

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

View File

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

View File

@ -8,7 +8,10 @@ use lox_cli::{get_lox_pub, networking::Networking};
use lox_library::{cred::Lox, scalar_u32};
use rand::Rng;
use serde::Deserialize;
use std::collections::{HashMap, HashSet};
use std::{
cmp::min,
collections::{HashMap, HashSet},
};
pub struct Censor {
pub known_bridges: HashSet<[u8; 20]>,
@ -112,17 +115,22 @@ impl Censor {
config.country.clone(),
)
.unwrap();
config
if config
.tp_net
.request("/positivereport".to_string(), pr.to_json().into_bytes())
.await;
.await
.is_err()
{
// failed to send positive report
return false;
}
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
if config.censor_hides == Hides::Flooding {
if config.censor_secrecy == Secrecy::Flooding {
for fingerprint in &self.known_bridges {
// Only do this if we're blocking the bridge
if config.censor_speed == Speed::Fast
@ -156,6 +164,38 @@ 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) {
// Only do this if Random censor
if config.censor_speed == Speed::Random
@ -175,10 +215,14 @@ impl Censor {
config: &Config,
bridges: &mut HashMap<[u8; 20], Bridge>,
) {
if config.censor_hides == Hides::Flooding
if config.censor_secrecy == Secrecy::Flooding
&& !(config.censor_speed == Speed::Random && self.delay_date <= get_date())
{
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);
@ -193,7 +237,7 @@ pub enum Speed {
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
pub enum Hides {
pub enum Secrecy {
Overt,
Hiding,
Flooding,

View File

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

View File

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