From 9992e3c73c0ff23df2c494316488b5e45c03f5f8 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Tue, 15 Nov 2022 19:11:16 -0500 Subject: [PATCH 01/39] Simple lox server Right now only issues open invite tokens --- crates/lox-distributor/.gitignore | 1 + crates/lox-distributor/Cargo.toml | 16 +++++++ crates/lox-distributor/src/main.rs | 71 ++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 crates/lox-distributor/.gitignore create mode 100644 crates/lox-distributor/Cargo.toml create mode 100644 crates/lox-distributor/src/main.rs diff --git a/crates/lox-distributor/.gitignore b/crates/lox-distributor/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/crates/lox-distributor/.gitignore @@ -0,0 +1 @@ +/target diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml new file mode 100644 index 0000000..77910e3 --- /dev/null +++ b/crates/lox-distributor/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "lox-server" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +hyper = "0.13" +tokio = { version = "0.2", features = ["macros", "signal"] } + +serde = "1" +serde_with = "1.9.1" +serde_json = "1.0.87" + +lox = { git = "https://git-crysp.uwaterloo.ca/iang/lox.git" } diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs new file mode 100644 index 0000000..ce9033b --- /dev/null +++ b/crates/lox-distributor/src/main.rs @@ -0,0 +1,71 @@ +use std::{ + net::SocketAddr, + sync::{Arc, Mutex}, + convert::Infallible, +}; + +use hyper::{ + service::{make_service_fn, service_fn}, + Body, Request, Server, Response, +}; + +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +use serde_json; + +use lox::{BridgeDb, OPENINV_LENGTH}; + +#[serde_as] +#[derive(Serialize, Deserialize)] +pub struct Invite { + #[serde_as(as = "[_; OPENINV_LENGTH]")] + invite: [u8; OPENINV_LENGTH], +} + +#[tokio::main] +async fn main() { + + // Create and initialize a new db + let mut bridgedb = BridgeDb::new(); + for i in &[1u32, 5, 7, 12, 19, 20, 22] { + bridgedb.insert_openinv(*i); + } + + let db = Arc::new(Mutex::new(bridgedb)); + + let new_service = make_service_fn(move |_conn| { + let db = db.clone(); + async move { + Ok::<_, Infallible>(service_fn(move |_req: Request| { + let db = db.clone(); + async move { + Ok::<_, Infallible>(generate_invite(db)) + } + })) + } + }); + + let addr = SocketAddr::from(([127, 0, 0, 1], 8001)); + let server = Server::bind(&addr).serve(new_service); + let graceful = server.with_graceful_shutdown(shutdown_signal()); + println!("Listening on {}", addr); + + if let Err(e) = graceful.await { + eprintln!("server error: {}", e); + } +} + +async fn shutdown_signal() { + tokio::signal::ctrl_c() + .await + .expect("failed to listen for ctrl+c signal"); +} + +fn generate_invite(db: Arc>) -> Response { + let obj = db.lock().unwrap(); + let invite = Invite { + invite: obj.invite(), + }; + let token = serde_json::to_string(&invite).unwrap(); + Response::new(Body::from(token)) +} From b97310c35bb67ffd16d0e260520983a2d0262557 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Tue, 15 Nov 2022 22:04:04 -0500 Subject: [PATCH 02/39] Add Access-Control-Allow-Origin header --- crates/lox-distributor/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index ce9033b..f7b4556 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -6,6 +6,7 @@ use std::{ use hyper::{ service::{make_service_fn, service_fn}, + header::HeaderValue, Body, Request, Server, Response, }; @@ -67,5 +68,7 @@ fn generate_invite(db: Arc>) -> Response { invite: obj.invite(), }; let token = serde_json::to_string(&invite).unwrap(); - Response::new(Body::from(token)) + let mut resp = Response::new(Body::from(token)); + resp.headers_mut().insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp } From bb5bdac588bbd3501312582139a7b0ffc51e337d Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Tue, 15 Nov 2022 22:05:02 -0500 Subject: [PATCH 03/39] Added README --- crates/lox-distributor/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 crates/lox-distributor/README.md diff --git a/crates/lox-distributor/README.md b/crates/lox-distributor/README.md new file mode 100644 index 0000000..3783e31 --- /dev/null +++ b/crates/lox-distributor/README.md @@ -0,0 +1,3 @@ +# Lox server + +Simply run `cargo run` :) From f80a6c80ebeaf69798032d065981e69387b049e1 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Wed, 25 Jan 2023 15:34:43 -0500 Subject: [PATCH 04/39] Adds bridge authority and placeholder buckets --- crates/lox-distributor/Cargo.toml | 4 +- crates/lox-distributor/src/main.rs | 79 ++++++++++++++++++++++++------ 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index 77910e3..5562358 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -6,9 +6,11 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +base64 = "0.13" hyper = "0.13" +hex_fmt = "0.3" tokio = { version = "0.2", features = ["macros", "signal"] } - +rand = "0.7" serde = "1" serde_with = "1.9.1" serde_json = "1.0.87" diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index f7b4556..5ef6842 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -1,20 +1,21 @@ use std::{ + convert::Infallible, net::SocketAddr, sync::{Arc, Mutex}, - convert::Infallible, }; use hyper::{ - service::{make_service_fn, service_fn}, header::HeaderValue, - Body, Request, Server, Response, + service::{make_service_fn, service_fn}, + Body, Request, Response, Server, }; - +use rand::RngCore; use serde::{Deserialize, Serialize}; -use serde_with::serde_as; use serde_json; +use serde_with::serde_as; -use lox::{BridgeDb, OPENINV_LENGTH}; +use lox::bridge_table::BridgeLine; +use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; #[serde_as] #[derive(Serialize, Deserialize)] @@ -23,15 +24,66 @@ pub struct Invite { invite: [u8; OPENINV_LENGTH], } +/// Create a random BridgeLine for testing ONLY. Do not use in production! +/// This was copied directly from lox/src/bridge_table.rs in order +/// to easily initialize a bridgedb/bridgeauth with structurally +/// correct buckets to be used for Lox requests/verifications/responses. +/// In production, existing bridges should be translated into this format +/// in a private function and sorted into buckets (3 bridges/bucket is suggested +/// but experience may suggest something else) in some intelligent way. + +pub fn random() -> BridgeLine { + let mut rng = rand::thread_rng(); + let mut res: BridgeLine = BridgeLine::default(); + // Pick a random 4-byte address + let mut addr: [u8; 4] = [0; 4]; + rng.fill_bytes(&mut addr); + // If the leading byte is 224 or more, that's not a valid IPv4 + // address. Choose an IPv6 address instead (but don't worry too + // much about it being well formed). + if addr[0] >= 224 { + rng.fill_bytes(&mut res.addr); + } else { + // Store an IPv4 address as a v4-mapped IPv6 address + res.addr[10] = 255; + res.addr[11] = 255; + res.addr[12..16].copy_from_slice(&addr); + }; + let ports: [u16; 4] = [443, 4433, 8080, 43079]; + let portidx = (rng.next_u32() % 4) as usize; + res.port = ports[portidx]; + let mut fingerprint: [u8; 20] = [0; 20]; + let mut cert: [u8; 52] = [0; 52]; + rng.fill_bytes(&mut fingerprint); + rng.fill_bytes(&mut cert); + let infostr: String = format!( + "obfs4 {} cert={} iat-mode=0", + hex_fmt::HexFmt(fingerprint), + base64::encode_config(cert, base64::STANDARD_NO_PAD) + ); + res.info[..infostr.len()].copy_from_slice(infostr.as_bytes()); + res +} + #[tokio::main] async fn main() { - - // Create and initialize a new db + let num_buckets = 5; + // Create and initialize a new db and bridgeauth let mut bridgedb = BridgeDb::new(); - for i in &[1u32, 5, 7, 12, 19, 20, 22] { - bridgedb.insert_openinv(*i); + let mut bridgeauth = BridgeAuth::new(bridgedb.pubkey); + // Make 3 x num_buckets open invitation bridges, in sets of 3 + for _ in 0..num_buckets { + let bucket = [ + random(), + random(), + random(), + ]; + bridgeauth.add_openinv_bridges(bucket, &mut bridgedb); } + // Create the encrypted bridge table + bridgeauth.enc_bridge_table(); + let db = Arc::new(Mutex::new(bridgedb)); let new_service = make_service_fn(move |_conn| { @@ -39,9 +91,7 @@ async fn main() { async move { Ok::<_, Infallible>(service_fn(move |_req: Request| { let db = db.clone(); - async move { - Ok::<_, Infallible>(generate_invite(db)) - } + async move { Ok::<_, Infallible>(generate_invite(db)) } })) } }); @@ -69,6 +119,7 @@ fn generate_invite(db: Arc>) -> Response { }; let token = serde_json::to_string(&invite).unwrap(); let mut resp = Response::new(Body::from(token)); - resp.headers_mut().insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp.headers_mut() + .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp } From 0f0f13df0d7e79f4c4ee5b2b86d2d5a13b7e12f2 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Wed, 25 Jan 2023 15:23:28 -0500 Subject: [PATCH 05/39] Tentative structure for request handler --- crates/lox-distributor/.gitignore | 1 + crates/lox-distributor/Cargo.toml | 2 +- crates/lox-distributor/src/main.rs | 108 +++++++++++++++++++++++------ 3 files changed, 87 insertions(+), 24 deletions(-) diff --git a/crates/lox-distributor/.gitignore b/crates/lox-distributor/.gitignore index ea8c4bf..96ef6c0 100644 --- a/crates/lox-distributor/.gitignore +++ b/crates/lox-distributor/.gitignore @@ -1 +1,2 @@ /target +Cargo.lock diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index 5562358..c82ba43 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -15,4 +15,4 @@ serde = "1" serde_with = "1.9.1" serde_json = "1.0.87" -lox = { git = "https://git-crysp.uwaterloo.ca/iang/lox.git" } +lox = { git = "https://gitlab.torproject.org/onyinyang/lox.git"} \ No newline at end of file diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 5ef6842..ccf4c21 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -6,16 +6,19 @@ use std::{ use hyper::{ header::HeaderValue, + server::conn::AddrStream, service::{make_service_fn, service_fn}, - Body, Request, Response, Server, + Body, Method, Request, Response, Server, StatusCode, }; +use lox::bridge_table::BridgeLine; +use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; use serde::{Deserialize, Serialize}; use serde_json; use serde_with::serde_as; - -use lox::bridge_table::BridgeLine; -use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; +use std::fs::File; +use std::io::Write; +use std::path::Path; #[serde_as] #[derive(Serialize, Deserialize)] @@ -26,7 +29,7 @@ pub struct Invite { /// Create a random BridgeLine for testing ONLY. Do not use in production! /// This was copied directly from lox/src/bridge_table.rs in order -/// to easily initialize a bridgedb/bridgeauth with structurally +/// to easily initialize a bridgedb/lox_auth with structurally /// correct buckets to be used for Lox requests/verifications/responses. /// In production, existing bridges should be translated into this format /// in a private function and sorted into buckets (3 bridges/bucket is suggested @@ -65,35 +68,86 @@ pub fn random() -> BridgeLine { res } +#[derive(Clone)] +struct LoxServerContext { + pubkey_filename: String, + db: Arc>, + ba: Arc>, +} + +async fn handle( + context: LoxServerContext, + // addr: SocketAddr, + req: Request, +) -> Result, Infallible> { + match (req.method(), req.uri().path()) { + (&Method::GET, "/") | (&Method::GET, "/index.html") => { + Ok::<_, Infallible>(generate_invite(context.db)) + } + (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(&context.pubkey_filename)), + //(&Method::POST, "/json_api") => api_post_response(req).await, + //(&Method::GET, "/json_api") => api_get_response().await, + _ => { + // Return 404 not found response. + Ok(Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::from("Not found")) + .unwrap()) + } + } +} + #[tokio::main] async fn main() { + let lox_auth_pubkeys_filename = "lox_auth_pubkeys.json"; let num_buckets = 5; - // Create and initialize a new db and bridgeauth + // Create and initialize a new db and lox_auth let mut bridgedb = BridgeDb::new(); - let mut bridgeauth = BridgeAuth::new(bridgedb.pubkey); + let mut lox_auth = BridgeAuth::new(bridgedb.pubkey); // Make 3 x num_buckets open invitation bridges, in sets of 3 for _ in 0..num_buckets { - let bucket = [ - random(), - random(), - random(), - ]; - bridgeauth.add_openinv_bridges(bucket, &mut bridgedb); + let bucket = [random(), random(), random()]; + lox_auth.add_openinv_bridges(bucket, &mut bridgedb); } // Create the encrypted bridge table - bridgeauth.enc_bridge_table(); + lox_auth.enc_bridge_table(); - let db = Arc::new(Mutex::new(bridgedb)); + // output lox_auth pubkeys if the file doesn't exist + if !Path::new(lox_auth_pubkeys_filename).exists() { + // vector of public keys (to serialize) + let lox_auth_pubkeys = vec![ + &lox_auth.lox_pub, + &lox_auth.migration_pub, + &lox_auth.migrationkey_pub, + &lox_auth.reachability_pub, + &lox_auth.invitation_pub, + ]; - let new_service = make_service_fn(move |_conn| { - let db = db.clone(); - async move { - Ok::<_, Infallible>(service_fn(move |_req: Request| { - let db = db.clone(); - async move { Ok::<_, Infallible>(generate_invite(db)) } - })) - } + // output lox_auth public keys + let mut lox_auth_pubkeys_outfile = File::create(lox_auth_pubkeys_filename) + .expect("Failed to create lox_auth pubkeys file"); + write!( + lox_auth_pubkeys_outfile, + "{}", + serde_json::to_string(&lox_auth_pubkeys).unwrap() + ) + .expect("Failed to write to lox_auth pubkeys file"); + } + + let context = LoxServerContext { + pubkey_filename: lox_auth_pubkeys_filename.into(), + db: Arc::new(Mutex::new(bridgedb)), + ba: Arc::new(Mutex::new(lox_auth)), + }; + + let new_service = make_service_fn(move |_conn: &AddrStream| { + let context = context.clone(); + let service = service_fn(move |req| { + // let addr = conn.remote_addr(); + handle(context.clone(), req) + }); + async move { Ok::<_, Infallible>(service) } }); let addr = SocketAddr::from(([127, 0, 0, 1], 8001)); @@ -123,3 +177,11 @@ fn generate_invite(db: Arc>) -> Response { .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp } + +fn send_keys(pubkeys_filename: &str) -> Response { + let json_keys = serde_json::to_string(pubkeys_filename).expect("JSON was not well-formatted"); + let mut resp = Response::new(Body::from(json_keys)); + resp.headers_mut() + .insert("Content-Type", HeaderValue::from_static("application/json")); + resp +} From 61940bdfe3f48be1fd3271edbbc712a74d12348d Mon Sep 17 00:00:00 2001 From: onyinyang Date: Wed, 25 Jan 2023 15:37:33 -0500 Subject: [PATCH 06/39] Sends pubkeys on request --- crates/lox-distributor/src/main.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index ccf4c21..aa5772c 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -10,6 +10,7 @@ use hyper::{ service::{make_service_fn, service_fn}, Body, Method, Request, Response, Server, StatusCode, }; +use std::fs; use lox::bridge_table::BridgeLine; use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; @@ -80,10 +81,10 @@ async fn handle( // addr: SocketAddr, req: Request, ) -> Result, Infallible> { + + println!("Reqs on {}, {}", req.method(), req.uri().path()); match (req.method(), req.uri().path()) { - (&Method::GET, "/") | (&Method::GET, "/index.html") => { - Ok::<_, Infallible>(generate_invite(context.db)) - } + (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(&context.pubkey_filename)), //(&Method::POST, "/json_api") => api_post_response(req).await, //(&Method::GET, "/json_api") => api_get_response().await, @@ -179,9 +180,10 @@ fn generate_invite(db: Arc>) -> Response { } fn send_keys(pubkeys_filename: &str) -> Response { - let json_keys = serde_json::to_string(pubkeys_filename).expect("JSON was not well-formatted"); + let data = fs::read_to_string(pubkeys_filename).expect("Unable to read file"); + let json_keys = serde_json::to_string(&data).expect("JSON was not well-formatted"); let mut resp = Response::new(Body::from(json_keys)); resp.headers_mut() - .insert("Content-Type", HeaderValue::from_static("application/json")); + .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp } From 77d4f8b164821e82fb53e33af330f73a0b0561d9 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 30 Jan 2023 18:14:22 -0500 Subject: [PATCH 07/39] Handle POST requests and open invite credential request --- crates/lox-distributor/src/main.rs | 110 ++++++++++++++++++----------- 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index aa5772c..005a818 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -1,3 +1,4 @@ +use core::slice; use std::{ convert::Infallible, net::SocketAddr, @@ -5,18 +6,20 @@ use std::{ }; use hyper::{ + body, body::Bytes, header::HeaderValue, server::conn::AddrStream, service::{make_service_fn, service_fn}, Body, Method, Request, Response, Server, StatusCode, }; -use std::fs; use lox::bridge_table::BridgeLine; +use lox::proto; use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; use serde::{Deserialize, Serialize}; use serde_json; use serde_with::serde_as; +use std::fs; use std::fs::File; use std::io::Write; use std::path::Path; @@ -81,23 +84,75 @@ async fn handle( // addr: SocketAddr, req: Request, ) -> Result, Infallible> { - println!("Reqs on {}, {}", req.method(), req.uri().path()); - match (req.method(), req.uri().path()) { - (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), - (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(&context.pubkey_filename)), - //(&Method::POST, "/json_api") => api_post_response(req).await, - //(&Method::GET, "/json_api") => api_get_response().await, - _ => { - // Return 404 not found response. - Ok(Response::builder() - .status(StatusCode::NOT_FOUND) - .body(Body::from("Not found")) - .unwrap()) - } + println!("Whole req: {:?}", req); + + match req.method() { + &Method::OPTIONS => Ok(Response::builder() + .header("Access-Control-Allow-Origin", HeaderValue::from_static("*")) + .header("Access-Control-Allow-Headers", "accept, content-type") + .header("Access-Control-Allow-Methods", "POST") + .status(200) + .body(Body::from("Allow POST")) + .unwrap()), + _ => match (req.method(), req.uri().path()) { + (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), + (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(&context.pubkey_filename)), + //TODO: figure out the format of the request and parse it? + (&Method::POST, "/openreq") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + verify_and_send_open_cred(bytes, context.ba) + }), + //(&Method::POST, "/json_api") => api_post_response(req).await, + //(&Method::GET, "/json_api") => api_get_response().await, + _ => { + // Return 404 not found response. + Ok(Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::from("Not found")) + .unwrap()) + } + }, } } +fn generate_invite(db: Arc>) -> Response { + let obj = db.lock().unwrap(); + let invite = Invite { + invite: obj.invite(), + }; + let token = serde_json::to_string(&invite).unwrap(); + let mut resp = Response::new(Body::from(token)); + resp.headers_mut() + .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp +} + +fn send_keys(pubkeys_filename: &str) -> Response { + let data = fs::read_to_string(pubkeys_filename).expect("Unable to read file"); + let json_keys = serde_json::to_string(&data).expect("JSON was not well-formatted"); + let mut resp = Response::new(Body::from(json_keys)); + resp.headers_mut() + .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp +} +fn verify_and_send_open_cred(request: Bytes, ba: Arc>) -> Response { + let req: proto::open_invite::Request = serde_json::from_slice(&request).unwrap(); + let mut ba_obj = ba.lock().unwrap(); + let response = ba_obj.handle_open_invite(req).unwrap(); + let open_invite_resp_str = serde_json::to_string(&response).unwrap(); + let mut resp = Response::new(Body::from(open_invite_resp_str)); + resp.headers_mut() + .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp +} + +async fn shutdown_signal() { + tokio::signal::ctrl_c() + .await + .expect("failed to listen for ctrl+c signal"); +} + #[tokio::main] async fn main() { let lox_auth_pubkeys_filename = "lox_auth_pubkeys.json"; @@ -160,30 +215,3 @@ async fn main() { eprintln!("server error: {}", e); } } - -async fn shutdown_signal() { - tokio::signal::ctrl_c() - .await - .expect("failed to listen for ctrl+c signal"); -} - -fn generate_invite(db: Arc>) -> Response { - let obj = db.lock().unwrap(); - let invite = Invite { - invite: obj.invite(), - }; - let token = serde_json::to_string(&invite).unwrap(); - let mut resp = Response::new(Body::from(token)); - resp.headers_mut() - .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); - resp -} - -fn send_keys(pubkeys_filename: &str) -> Response { - let data = fs::read_to_string(pubkeys_filename).expect("Unable to read file"); - let json_keys = serde_json::to_string(&data).expect("JSON was not well-formatted"); - let mut resp = Response::new(Body::from(json_keys)); - resp.headers_mut() - .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); - resp -} From 04b4d50ef90cf6fb3cc087c89a5fe924f88982ef Mon Sep 17 00:00:00 2001 From: onyinyang Date: Wed, 1 Feb 2023 00:44:18 -0500 Subject: [PATCH 08/39] Change keys to string to be handled properly in index.js --- crates/lox-distributor/src/main.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 005a818..823d85a 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -6,7 +6,8 @@ use std::{ }; use hyper::{ - body, body::Bytes, + body, + body::Bytes, header::HeaderValue, server::conn::AddrStream, service::{make_service_fn, service_fn}, @@ -130,12 +131,12 @@ fn generate_invite(db: Arc>) -> Response { fn send_keys(pubkeys_filename: &str) -> Response { let data = fs::read_to_string(pubkeys_filename).expect("Unable to read file"); - let json_keys = serde_json::to_string(&data).expect("JSON was not well-formatted"); - let mut resp = Response::new(Body::from(json_keys)); + let mut resp = Response::new(Body::from(serde_json::to_string(&data).unwrap())); resp.headers_mut() .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp } + fn verify_and_send_open_cred(request: Bytes, ba: Arc>) -> Response { let req: proto::open_invite::Request = serde_json::from_slice(&request).unwrap(); let mut ba_obj = ba.lock().unwrap(); From 9f0d0203a0d80989998ae987035f1d200b144ccb Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 6 Feb 2023 13:57:23 -0500 Subject: [PATCH 09/39] Fix issue with public key request --- crates/lox-distributor/src/main.rs | 51 ++++++++---------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 823d85a..7bba4af 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -1,4 +1,3 @@ -use core::slice; use std::{ convert::Infallible, net::SocketAddr, @@ -20,10 +19,6 @@ use rand::RngCore; use serde::{Deserialize, Serialize}; use serde_json; use serde_with::serde_as; -use std::fs; -use std::fs::File; -use std::io::Write; -use std::path::Path; #[serde_as] #[derive(Serialize, Deserialize)] @@ -75,7 +70,6 @@ pub fn random() -> BridgeLine { #[derive(Clone)] struct LoxServerContext { - pubkey_filename: String, db: Arc>, ba: Arc>, } @@ -85,9 +79,7 @@ async fn handle( // addr: SocketAddr, req: Request, ) -> Result, Infallible> { - println!("Reqs on {}, {}", req.method(), req.uri().path()); - println!("Whole req: {:?}", req); - + println!("Request: {:?}", req); match req.method() { &Method::OPTIONS => Ok(Response::builder() .header("Access-Control-Allow-Origin", HeaderValue::from_static("*")) @@ -98,7 +90,7 @@ async fn handle( .unwrap()), _ => match (req.method(), req.uri().path()) { (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), - (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(&context.pubkey_filename)), + (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(context.ba)), //TODO: figure out the format of the request and parse it? (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); @@ -129,9 +121,18 @@ fn generate_invite(db: Arc>) -> Response { resp } -fn send_keys(pubkeys_filename: &str) -> Response { - let data = fs::read_to_string(pubkeys_filename).expect("Unable to read file"); - let mut resp = Response::new(Body::from(serde_json::to_string(&data).unwrap())); +fn send_keys(ba: Arc>) -> Response { + let ba_obj = ba.lock().unwrap(); + // vector of public keys (to serialize) + let ba_obj_pubkeys = vec![ + &ba_obj.lox_pub, + &ba_obj.migration_pub, + &ba_obj.migrationkey_pub, + &ba_obj.reachability_pub, + &ba_obj.invitation_pub, + ]; + + let mut resp = Response::new(Body::from(serde_json::to_string(&ba_obj_pubkeys).unwrap())); resp.headers_mut() .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp @@ -156,7 +157,6 @@ async fn shutdown_signal() { #[tokio::main] async fn main() { - let lox_auth_pubkeys_filename = "lox_auth_pubkeys.json"; let num_buckets = 5; // Create and initialize a new db and lox_auth let mut bridgedb = BridgeDb::new(); @@ -170,30 +170,7 @@ async fn main() { // Create the encrypted bridge table lox_auth.enc_bridge_table(); - // output lox_auth pubkeys if the file doesn't exist - if !Path::new(lox_auth_pubkeys_filename).exists() { - // vector of public keys (to serialize) - let lox_auth_pubkeys = vec![ - &lox_auth.lox_pub, - &lox_auth.migration_pub, - &lox_auth.migrationkey_pub, - &lox_auth.reachability_pub, - &lox_auth.invitation_pub, - ]; - - // output lox_auth public keys - let mut lox_auth_pubkeys_outfile = File::create(lox_auth_pubkeys_filename) - .expect("Failed to create lox_auth pubkeys file"); - write!( - lox_auth_pubkeys_outfile, - "{}", - serde_json::to_string(&lox_auth_pubkeys).unwrap() - ) - .expect("Failed to write to lox_auth pubkeys file"); - } - let context = LoxServerContext { - pubkey_filename: lox_auth_pubkeys_filename.into(), db: Arc::new(Mutex::new(bridgedb)), ba: Arc::new(Mutex::new(lox_auth)), }; From f4e34c06b10e9646606fe8c9849f4e353271a768 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 6 Feb 2023 17:41:26 -0500 Subject: [PATCH 10/39] Add server side for trust promo requests --- crates/lox-distributor/src/main.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 7bba4af..1db0ba5 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -90,14 +90,16 @@ async fn handle( .unwrap()), _ => match (req.method(), req.uri().path()) { (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), + (&Method::GET, "/reachability") => Ok::<_, Infallible>(send_reachability_cred(context.ba)), (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(context.ba)), - //TODO: figure out the format of the request and parse it? (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); verify_and_send_open_cred(bytes, context.ba) }), - //(&Method::POST, "/json_api") => api_post_response(req).await, - //(&Method::GET, "/json_api") => api_get_response().await, + (&Method::POST, "/trustpromo") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + verify_and_send_trust_promo(bytes, context.ba) + }), _ => { // Return 404 not found response. Ok(Response::builder() @@ -121,6 +123,13 @@ fn generate_invite(db: Arc>) -> Response { resp } +fn send_reachability_cred(ba: Arc>) -> Response { + let ba_obj = ba.lock().unwrap(); + let mut resp = Response::new(Body::from(serde_json::to_string(&ba_obj.reachability_pub).unwrap())); + resp.headers_mut().insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp +} + fn send_keys(ba: Arc>) -> Response { let ba_obj = ba.lock().unwrap(); // vector of public keys (to serialize) @@ -149,6 +158,16 @@ fn verify_and_send_open_cred(request: Bytes, ba: Arc>) -> Resp resp } +fn verify_and_send_trust_promo(request: Bytes, ba: Arc>) -> Response { + let req: proto::trust_promotion::Request = serde_json::from_slice(&request).unwrap(); + let mut ba_obj = ba.lock().unwrap(); + let response = ba_obj.handle_trust_promotion(req).unwrap(); + let trust_promo_resp_str = serde_json::to_string(&response).unwrap(); + let mut resp = Response::new(Body::from(trust_promo_resp_str)); + resp.headers_mut() + .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp +} async fn shutdown_signal() { tokio::signal::ctrl_c() .await From 11071756d44b0bc05b0cacede6c1d36848fe6baa Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 13 Feb 2023 16:28:24 -0500 Subject: [PATCH 11/39] Add advance days for testing purposes --- crates/lox-distributor/Cargo.toml | 1 + crates/lox-distributor/src/main.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index c82ba43..bcf55c3 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -14,5 +14,6 @@ rand = "0.7" serde = "1" serde_with = "1.9.1" serde_json = "1.0.87" +time = "0.2" lox = { git = "https://gitlab.torproject.org/onyinyang/lox.git"} \ No newline at end of file diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 1db0ba5..9d356e7 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -116,6 +116,7 @@ fn generate_invite(db: Arc>) -> Response { let invite = Invite { invite: obj.invite(), }; + let token = serde_json::to_string(&invite).unwrap(); let mut resp = Response::new(Body::from(token)); resp.headers_mut() @@ -140,6 +141,7 @@ fn send_keys(ba: Arc>) -> Response { &ba_obj.reachability_pub, &ba_obj.invitation_pub, ]; + println!("Today's date according to server: {}", ba_obj.today()); let mut resp = Response::new(Body::from(serde_json::to_string(&ba_obj_pubkeys).unwrap())); resp.headers_mut() @@ -161,6 +163,8 @@ fn verify_and_send_open_cred(request: Bytes, ba: Arc>) -> Resp fn verify_and_send_trust_promo(request: Bytes, ba: Arc>) -> Response { let req: proto::trust_promotion::Request = serde_json::from_slice(&request).unwrap(); let mut ba_obj = ba.lock().unwrap(); + ba_obj.advance_days(31); + println!("Today's date according to server: {}", ba_obj.today()); let response = ba_obj.handle_trust_promotion(req).unwrap(); let trust_promo_resp_str = serde_json::to_string(&response).unwrap(); let mut resp = Response::new(Body::from(trust_promo_resp_str)); From 984bbe9370c930277b769a77d582c59da93c1abb Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 13 Feb 2023 23:58:38 -0500 Subject: [PATCH 12/39] Add trust migration server handling --- crates/lox-distributor/src/main.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 9d356e7..b03b6ef 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -100,6 +100,10 @@ async fn handle( let bytes = body::to_bytes(req.into_body()).await.unwrap(); verify_and_send_trust_promo(bytes, context.ba) }), + (&Method::POST, "/trustmig") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + verify_and_send_trust_migration(bytes, context.ba) + }), _ => { // Return 404 not found response. Ok(Response::builder() @@ -124,6 +128,7 @@ fn generate_invite(db: Arc>) -> Response { resp } + fn send_reachability_cred(ba: Arc>) -> Response { let ba_obj = ba.lock().unwrap(); let mut resp = Response::new(Body::from(serde_json::to_string(&ba_obj.reachability_pub).unwrap())); @@ -172,6 +177,18 @@ fn verify_and_send_trust_promo(request: Bytes, ba: Arc>) -> Re .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp } + +fn verify_and_send_trust_migration(request: Bytes, ba: Arc>) -> Response { + let req: proto::migration::Request = serde_json::from_slice(&request).unwrap(); + let mut ba_obj = ba.lock().unwrap(); + let response = ba_obj.handle_migration(req).unwrap(); + let trust_migration_resp_str = serde_json::to_string(&response).unwrap(); + let mut resp = Response::new(Body::from(trust_migration_resp_str)); + resp.headers_mut() + .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp +} + async fn shutdown_signal() { tokio::signal::ctrl_c() .await From a5b6ec8b93431b7e50f5dbadb8d4b85d7a3d983c Mon Sep 17 00:00:00 2001 From: onyinyang Date: Thu, 23 Feb 2023 01:00:53 -0500 Subject: [PATCH 13/39] Add request handling for encrypted bridge table and level up --- crates/lox-distributor/Cargo.toml | 2 +- crates/lox-distributor/src/main.rs | 59 +++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index bcf55c3..fe70cb6 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -11,7 +11,7 @@ hyper = "0.13" hex_fmt = "0.3" tokio = { version = "0.2", features = ["macros", "signal"] } rand = "0.7" -serde = "1" +serde = { version = "1.0", features = ["derive"] } serde_with = "1.9.1" serde_json = "1.0.87" time = "0.2" diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index b03b6ef..74d64c8 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -12,11 +12,12 @@ use hyper::{ service::{make_service_fn, service_fn}, Body, Method, Request, Response, Server, StatusCode, }; -use lox::bridge_table::BridgeLine; +use lox::bridge_table::{BridgeLine, ENC_BUCKET_BYTES}; use lox::proto; use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; use serde::{Deserialize, Serialize}; + use serde_json; use serde_with::serde_as; @@ -27,6 +28,13 @@ pub struct Invite { invite: [u8; OPENINV_LENGTH], } +#[serde_as] +#[derive(Serialize, Deserialize)] +pub struct EncBridgeTable { + #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")] + etable: Vec<[u8; ENC_BUCKET_BYTES]>, +} + /// Create a random BridgeLine for testing ONLY. Do not use in production! /// This was copied directly from lox/src/bridge_table.rs in order /// to easily initialize a bridgedb/lox_auth with structurally @@ -90,7 +98,9 @@ async fn handle( .unwrap()), _ => match (req.method(), req.uri().path()) { (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), - (&Method::GET, "/reachability") => Ok::<_, Infallible>(send_reachability_cred(context.ba)), + (&Method::GET, "/reachability") => { + Ok::<_, Infallible>(send_reachability_cred(context.ba)) + } (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(context.ba)), (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); @@ -104,6 +114,10 @@ async fn handle( let bytes = body::to_bytes(req.into_body()).await.unwrap(); verify_and_send_trust_migration(bytes, context.ba) }), + (&Method::POST, "/levelup") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + verify_and_send_level_up(bytes, context.ba) + }), _ => { // Return 404 not found response. Ok(Response::builder() @@ -128,11 +142,16 @@ fn generate_invite(db: Arc>) -> Response { resp } - +// Return the serialized encrypted bridge table fn send_reachability_cred(ba: Arc>) -> Response { - let ba_obj = ba.lock().unwrap(); - let mut resp = Response::new(Body::from(serde_json::to_string(&ba_obj.reachability_pub).unwrap())); - resp.headers_mut().insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + let mut ba_obj = ba.lock().unwrap(); + ba_obj.advance_days(85); // FOR TESTING ONLY + println!("Today's date according to server: {}", ba_obj.today()); + let enc_table = ba_obj.enc_bridge_table().clone(); + let etable = EncBridgeTable { etable: enc_table }; + let mut resp = Response::new(Body::from(serde_json::to_string(&etable).unwrap())); + resp.headers_mut() + .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp } @@ -159,31 +178,37 @@ fn verify_and_send_open_cred(request: Bytes, ba: Arc>) -> Resp let mut ba_obj = ba.lock().unwrap(); let response = ba_obj.handle_open_invite(req).unwrap(); let open_invite_resp_str = serde_json::to_string(&response).unwrap(); - let mut resp = Response::new(Body::from(open_invite_resp_str)); - resp.headers_mut() - .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); - resp + prepare_header(open_invite_resp_str) } fn verify_and_send_trust_promo(request: Bytes, ba: Arc>) -> Response { let req: proto::trust_promotion::Request = serde_json::from_slice(&request).unwrap(); let mut ba_obj = ba.lock().unwrap(); - ba_obj.advance_days(31); + ba_obj.advance_days(31); // FOR TESTING ONLY println!("Today's date according to server: {}", ba_obj.today()); let response = ba_obj.handle_trust_promotion(req).unwrap(); let trust_promo_resp_str = serde_json::to_string(&response).unwrap(); - let mut resp = Response::new(Body::from(trust_promo_resp_str)); - resp.headers_mut() - .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); - resp + prepare_header(trust_promo_resp_str) } fn verify_and_send_trust_migration(request: Bytes, ba: Arc>) -> Response { let req: proto::migration::Request = serde_json::from_slice(&request).unwrap(); let mut ba_obj = ba.lock().unwrap(); let response = ba_obj.handle_migration(req).unwrap(); - let trust_migration_resp_str = serde_json::to_string(&response).unwrap(); - let mut resp = Response::new(Body::from(trust_migration_resp_str)); + let resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(resp_str) +} + +fn verify_and_send_level_up(request: Bytes, ba: Arc>) -> Response { + let req: proto::level_up::Request = serde_json::from_slice(&request).unwrap(); + let mut ba_obj = ba.lock().unwrap(); + let response = ba_obj.handle_level_up(req).unwrap(); + let level_up_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(level_up_resp_str) +} + +fn prepare_header(response: String) -> Response { + let mut resp = Response::new(Body::from(response)); resp.headers_mut() .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp From fdaa75f43d770e77280d0ffc40e118644919d909 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Fri, 24 Feb 2023 19:10:38 -0500 Subject: [PATCH 14/39] Add issue invitation --- crates/lox-distributor/src/main.rs | 32 +++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 74d64c8..0e0f1fe 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -19,7 +19,7 @@ use rand::RngCore; use serde::{Deserialize, Serialize}; use serde_json; -use serde_with::serde_as; +use serde_with::{serde_as}; #[serde_as] #[derive(Serialize, Deserialize)] @@ -31,7 +31,7 @@ pub struct Invite { #[serde_as] #[derive(Serialize, Deserialize)] pub struct EncBridgeTable { - #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")] + #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")] etable: Vec<[u8; ENC_BUCKET_BYTES]>, } @@ -98,9 +98,7 @@ async fn handle( .unwrap()), _ => match (req.method(), req.uri().path()) { (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), - (&Method::GET, "/reachability") => { - Ok::<_, Infallible>(send_reachability_cred(context.ba)) - } + (&Method::GET, "/reachability") => Ok::<_, Infallible>(send_reachability_cred(context.ba)), (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(context.ba)), (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); @@ -118,6 +116,10 @@ async fn handle( let bytes = body::to_bytes(req.into_body()).await.unwrap(); verify_and_send_level_up(bytes, context.ba) }), + (&Method::POST, "/issueinvite") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + verify_and_send_issue_invite(bytes, context.ba) + }), _ => { // Return 404 not found response. Ok(Response::builder() @@ -129,6 +131,7 @@ async fn handle( } } + fn generate_invite(db: Arc>) -> Response { let obj = db.lock().unwrap(); let invite = Invite { @@ -145,13 +148,14 @@ fn generate_invite(db: Arc>) -> Response { // Return the serialized encrypted bridge table fn send_reachability_cred(ba: Arc>) -> Response { let mut ba_obj = ba.lock().unwrap(); - ba_obj.advance_days(85); // FOR TESTING ONLY + ba_obj.advance_days(85); // FOR TESTING ONLY println!("Today's date according to server: {}", ba_obj.today()); let enc_table = ba_obj.enc_bridge_table().clone(); - let etable = EncBridgeTable { etable: enc_table }; + let etable = EncBridgeTable { + etable: enc_table, + }; let mut resp = Response::new(Body::from(serde_json::to_string(&etable).unwrap())); - resp.headers_mut() - .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp.headers_mut().insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp } @@ -207,11 +211,21 @@ fn verify_and_send_level_up(request: Bytes, ba: Arc>) -> Respo prepare_header(level_up_resp_str) } +fn verify_and_send_issue_invite(request: Bytes, ba: Arc>) -> Response { + let req: proto::issue_invite::Request = serde_json::from_slice(&request).unwrap(); + let mut ba_obj = ba.lock().unwrap(); + let response = ba_obj.handle_issue_invite(req).unwrap(); + let issue_invite_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(issue_invite_resp_str) +} + + fn prepare_header(response: String) -> Response { let mut resp = Response::new(Body::from(response)); resp.headers_mut() .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp + } async fn shutdown_signal() { From 7bf91edbaacf4c5e6a520fcf201f63f32298c7f3 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 27 Feb 2023 14:17:07 -0500 Subject: [PATCH 15/39] Add redeem invite --- crates/lox-distributor/src/main.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 0e0f1fe..58f2252 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -120,6 +120,10 @@ async fn handle( let bytes = body::to_bytes(req.into_body()).await.unwrap(); verify_and_send_issue_invite(bytes, context.ba) }), + (&Method::POST, "/redeem") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + verify_and_send_redeem_invite(bytes, context.ba) + }), _ => { // Return 404 not found response. Ok(Response::builder() @@ -219,6 +223,15 @@ fn verify_and_send_issue_invite(request: Bytes, ba: Arc>) -> R prepare_header(issue_invite_resp_str) } +fn verify_and_send_redeem_invite(request: Bytes, ba: Arc>) -> Response { + let req: proto::redeem_invite::Request = serde_json::from_slice(&request).unwrap(); + let mut ba_obj = ba.lock().unwrap(); + let response = ba_obj.handle_redeem_invite(req).unwrap(); + let issue_invite_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(issue_invite_resp_str) +} + + fn prepare_header(response: String) -> Response { let mut resp = Response::new(Body::from(response)); From 9e2d3417519ce48d3ee7a190642710a189184de6 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Wed, 1 Mar 2023 20:05:51 -0500 Subject: [PATCH 16/39] Allow POST requests for invite tokens --- crates/lox-distributor/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 58f2252..7b275b0 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -98,6 +98,7 @@ async fn handle( .unwrap()), _ => match (req.method(), req.uri().path()) { (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), + (&Method::POST, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), (&Method::GET, "/reachability") => Ok::<_, Infallible>(send_reachability_cred(context.ba)), (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(context.ba)), (&Method::POST, "/openreq") => Ok::<_, Infallible>({ From 1018dd827f5d20a3907e7f5a23479062cfd389ef Mon Sep 17 00:00:00 2001 From: onyinyang Date: Fri, 3 Mar 2023 14:09:13 -0500 Subject: [PATCH 17/39] Add resourcediff stream stub for rdsys integration --- crates/lox-distributor/Cargo.toml | 7 ++- crates/lox-distributor/src/main.rs | 96 +++++++++++++++++++++++++----- 2 files changed, 86 insertions(+), 17 deletions(-) diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index fe70cb6..1e9f513 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -7,13 +7,14 @@ edition = "2021" [dependencies] base64 = "0.13" -hyper = "0.13" +hyper = { version = "0.14.24", features = ["server"] } hex_fmt = "0.3" -tokio = { version = "0.2", features = ["macros", "signal"] } +tokio = { version = "1", features = ["full", "macros", "signal"] } rand = "0.7" serde = { version = "1.0", features = ["derive"] } serde_with = "1.9.1" serde_json = "1.0.87" time = "0.2" -lox = { git = "https://gitlab.torproject.org/onyinyang/lox.git"} \ No newline at end of file +lox = { git = "https://gitlab.torproject.org/onyinyang/lox.git"} +rdsys_backend = { git = "https://gitlab.torproject.org/cohosh/rdsys-backend-api.git"} diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 7b275b0..3932211 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -16,10 +16,11 @@ use lox::bridge_table::{BridgeLine, ENC_BUCKET_BYTES}; use lox::proto; use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; +use rdsys_backend::start_stream; use serde::{Deserialize, Serialize}; use serde_json; -use serde_with::{serde_as}; +use serde_with::serde_as; #[serde_as] #[derive(Serialize, Deserialize)] @@ -31,10 +32,12 @@ pub struct Invite { #[serde_as] #[derive(Serialize, Deserialize)] pub struct EncBridgeTable { - #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")] + #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")] etable: Vec<[u8; ENC_BUCKET_BYTES]>, } +// Populate Bridgedb from rdsys + /// Create a random BridgeLine for testing ONLY. Do not use in production! /// This was copied directly from lox/src/bridge_table.rs in order /// to easily initialize a bridgedb/lox_auth with structurally @@ -98,8 +101,9 @@ async fn handle( .unwrap()), _ => match (req.method(), req.uri().path()) { (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), - (&Method::POST, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), - (&Method::GET, "/reachability") => Ok::<_, Infallible>(send_reachability_cred(context.ba)), + (&Method::GET, "/reachability") => { + Ok::<_, Infallible>(send_reachability_cred(context.ba)) + } (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(context.ba)), (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); @@ -125,6 +129,15 @@ async fn handle( let bytes = body::to_bytes(req.into_body()).await.unwrap(); verify_and_send_redeem_invite(bytes, context.ba) }), + (&Method::POST, "/checkblockage") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + // TEST ONLY: Block all existing bridges and add new ones for migration + verify_and_send_check_blockage(bytes, context.ba, context.db) + }), + (&Method::POST, "/blockagemigration") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + verify_and_send_blockage_migration(bytes, context.ba) + }), _ => { // Return 404 not found response. Ok(Response::builder() @@ -136,7 +149,6 @@ async fn handle( } } - fn generate_invite(db: Arc>) -> Response { let obj = db.lock().unwrap(); let invite = Invite { @@ -153,14 +165,13 @@ fn generate_invite(db: Arc>) -> Response { // Return the serialized encrypted bridge table fn send_reachability_cred(ba: Arc>) -> Response { let mut ba_obj = ba.lock().unwrap(); - ba_obj.advance_days(85); // FOR TESTING ONLY + ba_obj.advance_days(85); // FOR TESTING ONLY println!("Today's date according to server: {}", ba_obj.today()); let enc_table = ba_obj.enc_bridge_table().clone(); - let etable = EncBridgeTable { - etable: enc_table, - }; + let etable = EncBridgeTable { etable: enc_table }; let mut resp = Response::new(Body::from(serde_json::to_string(&etable).unwrap())); - resp.headers_mut().insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp.headers_mut() + .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp } @@ -228,18 +239,58 @@ fn verify_and_send_redeem_invite(request: Bytes, ba: Arc>) -> let req: proto::redeem_invite::Request = serde_json::from_slice(&request).unwrap(); let mut ba_obj = ba.lock().unwrap(); let response = ba_obj.handle_redeem_invite(req).unwrap(); - let issue_invite_resp_str = serde_json::to_string(&response).unwrap(); - prepare_header(issue_invite_resp_str) + let redeem_invite_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(redeem_invite_resp_str) } +fn verify_and_send_check_blockage( + request: Bytes, + ba: Arc>, + db: Arc>, +) -> Response { + let req: proto::check_blockage::Request = serde_json::from_slice(&request).unwrap(); + let mut ba_obj = ba.lock().unwrap(); + // Created 5 buckets initially, so we will add 5 hot spares (for migration) and + // block all of the existing buckets to trigger migration table propagation + // FOR TESTING ONLY, ADD 5 NEW Buckets + for _ in 0..5 { + let bucket = [random(), random(), random()]; + ba_obj.add_spare_bucket(bucket); + } + ba_obj.enc_bridge_table(); + // FOR TESTING ONLY, BLOCK ALL BRIDGES + let mut db_obj = db.lock().unwrap(); + for index in 0..5 { + let b0 = ba_obj.bridge_table.buckets[index][0]; + let b1 = ba_obj.bridge_table.buckets[index][1]; + let b2 = ba_obj.bridge_table.buckets[index][2]; + ba_obj.bridge_unreachable(&b0, &mut db_obj); + ba_obj.bridge_unreachable(&b1, &mut db_obj); + ba_obj.bridge_unreachable(&b2, &mut db_obj); + } + ba_obj.enc_bridge_table(); + let response = ba_obj.handle_check_blockage(req).unwrap(); + let check_blockage_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(check_blockage_resp_str) +} + +fn verify_and_send_blockage_migration( + request: Bytes, + ba: Arc>, +) -> Response { + let req: proto::blockage_migration::Request = serde_json::from_slice(&request).unwrap(); + let mut ba_obj = ba.lock().unwrap(); + let response = ba_obj.handle_blockage_migration(req).unwrap(); + let resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(resp_str) +} fn prepare_header(response: String) -> Response { let mut resp = Response::new(Body::from(response)); resp.headers_mut() .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp - } async fn shutdown_signal() { @@ -248,8 +299,25 @@ async fn shutdown_signal() { .expect("failed to listen for ctrl+c signal"); } -#[tokio::main] +// Initial bridgedb setup then: +// Listen for updates and return new bridges to be added to the bridgedb +async fn load_bridges() { + let endpoint = String::from("http://127.0.0.1:7100/resource-stream"); + let name = String::from("https"); + let token = String::from("HttpsApiTokenPlaceholder"); //Bring in from commmand line + let types = vec![String::from("obfs2"), String::from("scramblesuit")]; + let rx = start_stream(endpoint, name, token, types).await.unwrap(); + for diff in rx { + println!("Received diff: {:?}", diff); //send this through a channel + } +} + +#[tokio::main(worker_threads = 2)] async fn main() { + +// + tokio::spawn(async move { load_bridges().await; }); + // let new_bridgedb = task::spawn(load_bridges()); let num_buckets = 5; // Create and initialize a new db and lox_auth let mut bridgedb = BridgeDb::new(); From a7cf09f812a69f18259dd888d30c0aa29a336ee8 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Fri, 3 Mar 2023 17:25:43 -0500 Subject: [PATCH 18/39] Read json config from commandline file, progress on channels --- crates/lox-distributor/Cargo.toml | 2 +- crates/lox-distributor/config.json | 9 ++++ crates/lox-distributor/src/main.rs | 72 +++++++++++++++++++++--------- 3 files changed, 60 insertions(+), 23 deletions(-) create mode 100644 crates/lox-distributor/config.json diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index 1e9f513..3050f2b 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" base64 = "0.13" hyper = { version = "0.14.24", features = ["server"] } hex_fmt = "0.3" -tokio = { version = "1", features = ["full", "macros", "signal"] } +tokio = { version = "1", features = ["full", "macros", "signal", "sync"] } rand = "0.7" serde = { version = "1.0", features = ["derive"] } serde_with = "1.9.1" diff --git a/crates/lox-distributor/config.json b/crates/lox-distributor/config.json new file mode 100644 index 0000000..177e5a2 --- /dev/null +++ b/crates/lox-distributor/config.json @@ -0,0 +1,9 @@ +{ + "endpoint": "http://127.0.0.1:7100/resource-stream", + "name": "https", + "token": "HttpsApiTokenPlaceholder", + "types": [ + "obfs2", + "scramblesuit" + ] +} \ No newline at end of file diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 3932211..e3bbd23 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -1,9 +1,3 @@ -use std::{ - convert::Infallible, - net::SocketAddr, - sync::{Arc, Mutex}, -}; - use hyper::{ body, body::Bytes, @@ -16,11 +10,20 @@ use lox::bridge_table::{BridgeLine, ENC_BUCKET_BYTES}; use lox::proto; use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; -use rdsys_backend::start_stream; +use rdsys_backend::{proto::ResourceDiff, start_stream, ResourceStream}; use serde::{Deserialize, Serialize}; +use std::{ + convert::Infallible, + env, + fs::File, + io::BufReader, + net::SocketAddr, + sync::{Arc, Mutex}, +}; use serde_json; use serde_with::serde_as; +use tokio::{spawn, sync::mpsc}; #[serde_as] #[derive(Serialize, Deserialize)] @@ -36,6 +39,13 @@ pub struct EncBridgeTable { etable: Vec<[u8; ENC_BUCKET_BYTES]>, } +#[derive(Debug, Deserialize)] +struct ResourceInfo { + endpoint: String, + name: String, + token: String, + types: Vec, +} // Populate Bridgedb from rdsys /// Create a random BridgeLine for testing ONLY. Do not use in production! @@ -300,28 +310,46 @@ async fn shutdown_signal() { } // Initial bridgedb setup then: -// Listen for updates and return new bridges to be added to the bridgedb -async fn load_bridges() { - let endpoint = String::from("http://127.0.0.1:7100/resource-stream"); - let name = String::from("https"); - let token = String::from("HttpsApiTokenPlaceholder"); //Bring in from commmand line - let types = vec![String::from("obfs2"), String::from("scramblesuit")]; - let rx = start_stream(endpoint, name, token, types).await.unwrap(); - for diff in rx { - println!("Received diff: {:?}", diff); //send this through a channel - } -} +// Listen for updates and return new bridges to be added to the bridged +// Run with cargo run -- config.json #[tokio::main(worker_threads = 2)] async fn main() { + let args: Vec = env::args().collect(); + let file = File::open(&args[1]).expect("Should have been able to read config.json file"); + let reader = BufReader::new(file); + // Read the JSON contents of the file as a ResourceInfo + let rtype: ResourceInfo = serde_json::from_reader(reader).unwrap(); -// - tokio::spawn(async move { load_bridges().await; }); - // let new_bridgedb = task::spawn(load_bridges()); + // pass in distribution of open invite vs. hot spare buckets? let num_buckets = 5; - // Create and initialize a new db and lox_auth + let hot_spare_buckets = 5; let mut bridgedb = BridgeDb::new(); let mut lox_auth = BridgeAuth::new(bridgedb.pubkey); + + //Sender is resource stream and receiver is bridgedb function (add_openinv_bridges) + let (mut tx, mut rx) = mpsc::channel(100); + // to populate the bridge db + spawn(async move { + let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) + .await + .unwrap(); + for diff in rstream { + println!("Received diff: {:?}", diff); //send this through a channel + tx.send(diff).await.expect("can not add to bridgedb)") + } + }); + + spawn(async move { + while let Some(resourcediff) = rx.recv().await { + println!("received: {:?}", resourcediff); + //parse resource diff into Bridgeline + //add open inv bridges + // users.push(user); + } + }); + // let new_bridgedb = task::spawn(load_bridges()); + // Create and initialize a new db and lox_auth // Make 3 x num_buckets open invitation bridges, in sets of 3 for _ in 0..num_buckets { let bucket = [random(), random(), random()]; From be861baf364f831640120f889dee7f4a2e236be5 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Thu, 9 Mar 2023 19:01:01 -0500 Subject: [PATCH 19/39] Add parsing resource into Lox BridgeLine --- crates/lox-distributor/Cargo.toml | 3 +- crates/lox-distributor/src/main.rs | 56 ++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index 3050f2b..b89e896 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -6,10 +6,11 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +async-channel = "1.8.0" base64 = "0.13" hyper = { version = "0.14.24", features = ["server"] } hex_fmt = "0.3" -tokio = { version = "1", features = ["full", "macros", "signal", "sync"] } +tokio = { version = "1", features = ["full", "macros", "signal"] } rand = "0.7" serde = { version = "1.0", features = ["derive"] } serde_with = "1.9.1" diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index e3bbd23..a80cc2c 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -6,7 +6,7 @@ use hyper::{ service::{make_service_fn, service_fn}, Body, Method, Request, Response, Server, StatusCode, }; -use lox::bridge_table::{BridgeLine, ENC_BUCKET_BYTES}; +use lox::bridge_table::{BridgeLine, ENC_BUCKET_BYTES, BRIDGE_BYTES}; use lox::proto; use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; @@ -328,26 +328,68 @@ async fn main() { let mut lox_auth = BridgeAuth::new(bridgedb.pubkey); //Sender is resource stream and receiver is bridgedb function (add_openinv_bridges) - let (mut tx, mut rx) = mpsc::channel(100); + let (mut tx, mut rx) = async_channel::bounded(3); // to populate the bridge db - spawn(async move { - let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) + let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) .await .unwrap(); + spawn(async move { for diff in rstream { println!("Received diff: {:?}", diff); //send this through a channel tx.send(diff).await.expect("can not add to bridgedb)") } }); + while let resourcediff = rx.recv().await.unwrap() { spawn(async move { - while let Some(resourcediff) = rx.recv().await { - println!("received: {:?}", resourcediff); + for new_resource in resourcediff.new.unwrap(){ + println!("A NEW RESOURCE: {:?}", new_resource); + match new_resource.0.as_str() { + "obfs2" => { + println!("Obfs2!"); + let count = 0; + for resource in new_resource.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()].copy_from_slice(resource.address.as_bytes()); + //let params = resource.params.unwrap(); I guess this should be a cert but I will fix this later + let infostr: String = format!( + "obfs4 {} fingerprint={} cert={} iat-mode=0", + resource.r#type, + resource.fingerprint, + base64::encode_config("super secret password", base64::STANDARD_NO_PAD), + ); + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES-18]; + + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; + println!("Now it's a bridgeline: {:?}", bline); + } + }, + "scramblesuit" => println!("Scramblesuit!"), + "obfs4" => println!("Obfs4!"), + "meek" => println!("Meek!"), + "snowflake" => println!("Meek!"), + _=> println!("Other unknown"), + } + + + + } + for changed_resource in resourcediff.changed{ + println!("A NEW CHANGED RESOURCE: {:?}", changed_resource); + } + for gone_resource in resourcediff.gone{ + println!("A NEW GONE RESOURCE: {:?}", gone_resource); + } //parse resource diff into Bridgeline //add open inv bridges // users.push(user); + }); } - }); // let new_bridgedb = task::spawn(load_bridges()); // Create and initialize a new db and lox_auth // Make 3 x num_buckets open invitation bridges, in sets of 3 From b2642d353c418eb8b4ac25eeed0e315f6916cc06 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Fri, 10 Mar 2023 15:21:27 -0500 Subject: [PATCH 20/39] Add add_invitation_bucket for new bridgelines and remove gone bridgelines --- crates/lox-distributor/src/main.rs | 134 ++++++++++++++++++----------- 1 file changed, 85 insertions(+), 49 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index a80cc2c..084558e 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -6,7 +6,7 @@ use hyper::{ service::{make_service_fn, service_fn}, Body, Method, Request, Response, Server, StatusCode, }; -use lox::bridge_table::{BridgeLine, ENC_BUCKET_BYTES, BRIDGE_BYTES}; +use lox::bridge_table::{BridgeLine, BRIDGE_BYTES, ENC_BUCKET_BYTES}; use lox::proto; use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; @@ -331,8 +331,8 @@ async fn main() { let (mut tx, mut rx) = async_channel::bounded(3); // to populate the bridge db let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) - .await - .unwrap(); + .await + .unwrap(); spawn(async move { for diff in rstream { println!("Received diff: {:?}", diff); //send this through a channel @@ -340,56 +340,92 @@ async fn main() { } }); - while let resourcediff = rx.recv().await.unwrap() { - spawn(async move { - for new_resource in resourcediff.new.unwrap(){ - println!("A NEW RESOURCE: {:?}", new_resource); - match new_resource.0.as_str() { - "obfs2" => { - println!("Obfs2!"); - let count = 0; - for resource in new_resource.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()].copy_from_slice(resource.address.as_bytes()); - //let params = resource.params.unwrap(); I guess this should be a cert but I will fix this later - let infostr: String = format!( - "obfs4 {} fingerprint={} cert={} iat-mode=0", - resource.r#type, - resource.fingerprint, - base64::encode_config("super secret password", base64::STANDARD_NO_PAD), - ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES-18]; + while let resourcediff = rx.recv().await.unwrap() { + // spawn(async move { + for new_resource in resourcediff.new { + for pt in new_resource { + println!("A NEW RESOURCE: {:?}", pt); + let mut bucket = [ + BridgeLine::default(), + BridgeLine::default(), + BridgeLine::default(), + ]; + let mut count = 0; + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()].copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( + "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", + resource.r#type, + resource.blocked_in, + resource.protocol, + resource.fingerprint, + resource.or_addresses, + resource.distribution, + resource.flags, + resource.params, + ); + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bline = BridgeLine { - addr: ip_bytes, - port: resource.port, - info: info_bytes, - }; - println!("Now it's a bridgeline: {:?}", bline); - } - }, - "scramblesuit" => println!("Scramblesuit!"), - "obfs4" => println!("Obfs4!"), - "meek" => println!("Meek!"), - "snowflake" => println!("Meek!"), - _=> println!("Other unknown"), + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; + + println!("Now it's a bridgeline: {:?}", bridgeline); + if count < 2 { + bucket[count] = bridgeline; + count += 1; + } else { + lox_auth.add_openinv_bridges(bucket, &mut bridgedb); + count = 0; + bucket = [ + BridgeLine::default(), + BridgeLine::default(), + BridgeLine::default(), + ]; + } } - - - } - for changed_resource in resourcediff.changed{ - println!("A NEW CHANGED RESOURCE: {:?}", changed_resource); - } - for gone_resource in resourcediff.gone{ - println!("A NEW GONE RESOURCE: {:?}", gone_resource); - } - //parse resource diff into Bridgeline - //add open inv bridges - // users.push(user); - }); } + for changed_resource in resourcediff.changed { + println!("A NEW CHANGED RESOURCE: {:?}", changed_resource); + } + for gone_resource in resourcediff.gone { + for pt in gone_resource { + println!("A NEW GONE RESOURCE: {:?}", pt); + let mut unreachable_bridge = BridgeLine::default(); + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()].copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( + "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", + resource.r#type, + resource.blocked_in, + resource.protocol, + resource.fingerprint, + resource.or_addresses, + resource.distribution, + resource.flags, + resource.params, + ); + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; + + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; + + println!("Now it's a bridgeline: {:?}", bridgeline); + lox_auth.bridge_unreachable(&unreachable_bridge, &mut bridgedb); + } + } + } + } // let new_bridgedb = task::spawn(load_bridges()); // Create and initialize a new db and lox_auth // Make 3 x num_buckets open invitation bridges, in sets of 3 From c715d80632be0d0880f51c3630bc7ec3daf74391 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Fri, 10 Mar 2023 16:54:31 -0500 Subject: [PATCH 21/39] [WIP] Progress on bridgedb update through channel update --- crates/lox-distributor/src/main.rs | 37 ++++++++++++++++++------------ 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 084558e..4e4aa1a 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -322,13 +322,15 @@ async fn main() { let rtype: ResourceInfo = serde_json::from_reader(reader).unwrap(); // pass in distribution of open invite vs. hot spare buckets? - let num_buckets = 5; - let hot_spare_buckets = 5; - let mut bridgedb = BridgeDb::new(); - let mut lox_auth = BridgeAuth::new(bridgedb.pubkey); + let bridgedb = BridgeDb::new(); + let lox_auth = BridgeAuth::new(bridgedb.pubkey); + let context = LoxServerContext { + db: Arc::new(Mutex::new(bridgedb)), + ba: Arc::new(Mutex::new(lox_auth)), + }; //Sender is resource stream and receiver is bridgedb function (add_openinv_bridges) - let (mut tx, mut rx) = async_channel::bounded(3); + let (tx, rx) = async_channel::bounded(3); // to populate the bridge db let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) .await @@ -340,6 +342,8 @@ async fn main() { } }); + let context_clone = context.clone(); + let _ = spawn(async move { while let resourcediff = rx.recv().await.unwrap() { // spawn(async move { for new_resource in resourcediff.new { @@ -379,7 +383,9 @@ async fn main() { bucket[count] = bridgeline; count += 1; } else { - lox_auth.add_openinv_bridges(bucket, &mut bridgedb); + let mut ba_obj = context_clone.ba.lock().unwrap(); + let mut db_obj = context_clone.db.lock().unwrap(); + ba_obj.add_openinv_bridges(bucket, &mut db_obj); count = 0; bucket = [ BridgeLine::default(), @@ -421,31 +427,32 @@ async fn main() { }; println!("Now it's a bridgeline: {:?}", bridgeline); - lox_auth.bridge_unreachable(&unreachable_bridge, &mut bridgedb); + let mut ba_obj = context_clone.ba.lock().unwrap(); + let mut db_obj = context_clone.db.lock().unwrap(); + ba_obj.bridge_unreachable(&unreachable_bridge, &mut db_obj); } } } + // Create the encrypted bridge table + let mut ba_obj = context_clone.ba.lock().unwrap(); + ba_obj.enc_bridge_table(); } + }); // let new_bridgedb = task::spawn(load_bridges()); // Create and initialize a new db and lox_auth // Make 3 x num_buckets open invitation bridges, in sets of 3 - for _ in 0..num_buckets { +/* for _ in 0..num_buckets { let bucket = [random(), random(), random()]; lox_auth.add_openinv_bridges(bucket, &mut bridgedb); } +*/ + - // Create the encrypted bridge table - lox_auth.enc_bridge_table(); - let context = LoxServerContext { - db: Arc::new(Mutex::new(bridgedb)), - ba: Arc::new(Mutex::new(lox_auth)), - }; let new_service = make_service_fn(move |_conn: &AddrStream| { let context = context.clone(); let service = service_fn(move |req| { - // let addr = conn.remote_addr(); handle(context.clone(), req) }); async move { Ok::<_, Infallible>(service) } From 34f1d0399f172a966628367d4e4e31562588a69c Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 13 Mar 2023 18:05:52 -0400 Subject: [PATCH 22/39] Refactoring to add a channel to pass messages to client --- crates/lox-distributor/Cargo.toml | 2 +- crates/lox-distributor/src/main.rs | 499 +++++++++++++++++------------ 2 files changed, 290 insertions(+), 211 deletions(-) diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index b89e896..03930ce 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -10,12 +10,12 @@ async-channel = "1.8.0" base64 = "0.13" hyper = { version = "0.14.24", features = ["server"] } hex_fmt = "0.3" +futures = "0.3.26" tokio = { version = "1", features = ["full", "macros", "signal"] } rand = "0.7" serde = { version = "1.0", features = ["derive"] } serde_with = "1.9.1" serde_json = "1.0.87" -time = "0.2" lox = { git = "https://gitlab.torproject.org/onyinyang/lox.git"} rdsys_backend = { git = "https://gitlab.torproject.org/cohosh/rdsys-backend-api.git"} diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 4e4aa1a..b861b9c 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -1,3 +1,5 @@ +use async_channel::{Sender, Receiver}; +use futures::future; use hyper::{ body, body::Bytes, @@ -7,7 +9,13 @@ use hyper::{ Body, Method, Request, Response, Server, StatusCode, }; use lox::bridge_table::{BridgeLine, BRIDGE_BYTES, ENC_BUCKET_BYTES}; -use lox::proto; +use lox::{ + proto::{ + blockage_migration, check_blockage, issue_invite, level_up, migration, open_invite, + redeem_invite, trust_promotion, + }, + IssuerPubKey, +}; use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; use rdsys_backend::{proto::ResourceDiff, start_stream, ResourceStream}; @@ -19,11 +27,12 @@ use std::{ io::BufReader, net::SocketAddr, sync::{Arc, Mutex}, + time::Duration, }; use serde_json; use serde_with::serde_as; -use tokio::{spawn, sync::mpsc}; +use tokio::{spawn, time::sleep, sync::mpsc}; #[serde_as] #[derive(Serialize, Deserialize)] @@ -95,6 +104,110 @@ struct LoxServerContext { ba: Arc>, } +impl LoxServerContext { + fn add_openinv_bucket(&self, bucket: [BridgeLine; 3]) { + let mut ba_obj = self.ba.lock().unwrap(); + let mut db_obj = self.db.lock().unwrap(); + ba_obj.add_openinv_bridges(bucket, &mut db_obj); + } + + fn add_unreachable(&self, bridgeline: BridgeLine) { + let mut ba_obj = self.ba.lock().unwrap(); + let mut db_obj = self.db.lock().unwrap(); + ba_obj.bridge_unreachable(&bridgeline, &mut db_obj); + } + + fn advance_days_TEST(&self, num: u16) { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.advance_days(num); // FOR TESTING ONLY + println!("Today's date according to server: {}", ba_obj.today()); + } + + fn encrypt_table(&self) -> Vec<[u8; ENC_BUCKET_BYTES]> { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.enc_bridge_table().clone() + } + + fn pubkeys(&self) -> Vec { + let ba_obj = self.ba.lock().unwrap(); + // vector of public keys (to serialize) + vec![ + ba_obj.lox_pub.clone(), + ba_obj.migration_pub.clone(), + ba_obj.migrationkey_pub.clone(), + ba_obj.reachability_pub.clone(), + ba_obj.invitation_pub.clone(), + ] + } + + fn gen_invite(&self) -> Invite { + let obj = self.db.lock().unwrap(); + return Invite { + invite: obj.invite(), + }; + } + + fn open_inv(&self, req: open_invite::Request) -> open_invite::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_open_invite(req).unwrap() + } + + fn trust_promo(&self, req: trust_promotion::Request) -> trust_promotion::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_trust_promotion(req).unwrap() + } + + fn trust_migration(&self, req: migration::Request) -> migration::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_migration(req).unwrap() + } + + fn level_up(&self, req: level_up::Request) -> level_up::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_level_up(req).unwrap() + } + + fn issue_invite(&self, req: issue_invite::Request) -> issue_invite::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_issue_invite(req).unwrap() + } + + fn redeem_invite(&self, req: redeem_invite::Request) -> redeem_invite::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_redeem_invite(req).unwrap() + } + + fn check_blockage(&self, req: check_blockage::Request) -> check_blockage::Response { + let mut ba_obj = self.ba.lock().unwrap(); + // Created 5 buckets initially, so we will add 5 hot spares (for migration) and + // block all of the existing buckets to trigger migration table propagation + // FOR TESTING ONLY, ADD 5 NEW Buckets + for _ in 0..5 { + let bucket = [random(), random(), random()]; + ba_obj.add_spare_bucket(bucket); + } + ba_obj.enc_bridge_table(); + + // FOR TESTING ONLY, BLOCK ALL BRIDGES + let mut db_obj = self.db.lock().unwrap(); + for index in 0..5 { + let b0 = ba_obj.bridge_table.buckets[index][0]; + let b1 = ba_obj.bridge_table.buckets[index][1]; + let b2 = ba_obj.bridge_table.buckets[index][2]; + ba_obj.bridge_unreachable(&b0, &mut db_obj); + ba_obj.bridge_unreachable(&b1, &mut db_obj); + ba_obj.bridge_unreachable(&b2, &mut db_obj); + } + ba_obj.enc_bridge_table(); + ba_obj.handle_check_blockage(req).unwrap() + } + + fn blockage_migration(&self, req: blockage_migration::Request) -> blockage_migration::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_blockage_migration(req).unwrap() + } +} + async fn handle( context: LoxServerContext, // addr: SocketAddr, @@ -110,43 +223,41 @@ async fn handle( .body(Body::from("Allow POST")) .unwrap()), _ => match (req.method(), req.uri().path()) { - (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context.db)), - (&Method::GET, "/reachability") => { - Ok::<_, Infallible>(send_reachability_cred(context.ba)) - } - (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(context.ba)), + (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context)), + (&Method::GET, "/reachability") => Ok::<_, Infallible>(send_reachability_cred(context)), + (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(context)), (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_open_cred(bytes, context.ba) + verify_and_send_open_cred(bytes, context) }), (&Method::POST, "/trustpromo") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_trust_promo(bytes, context.ba) + verify_and_send_trust_promo(bytes, context) }), (&Method::POST, "/trustmig") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_trust_migration(bytes, context.ba) + verify_and_send_trust_migration(bytes, context) }), (&Method::POST, "/levelup") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_level_up(bytes, context.ba) + verify_and_send_level_up(bytes, context) }), (&Method::POST, "/issueinvite") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_issue_invite(bytes, context.ba) + verify_and_send_issue_invite(bytes, context) }), (&Method::POST, "/redeem") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_redeem_invite(bytes, context.ba) + verify_and_send_redeem_invite(bytes, context) }), (&Method::POST, "/checkblockage") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); // TEST ONLY: Block all existing bridges and add new ones for migration - verify_and_send_check_blockage(bytes, context.ba, context.db) + verify_and_send_check_blockage(bytes, context) }), (&Method::POST, "/blockagemigration") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_blockage_migration(bytes, context.ba) + verify_and_send_blockage_migration(bytes, context) }), _ => { // Return 404 not found response. @@ -159,12 +270,8 @@ async fn handle( } } -fn generate_invite(db: Arc>) -> Response { - let obj = db.lock().unwrap(); - let invite = Invite { - invite: obj.invite(), - }; - +fn generate_invite(context: LoxServerContext) -> Response { + let invite = context.gen_invite(); let token = serde_json::to_string(&invite).unwrap(); let mut resp = Response::new(Body::from(token)); resp.headers_mut() @@ -173,11 +280,9 @@ fn generate_invite(db: Arc>) -> Response { } // Return the serialized encrypted bridge table -fn send_reachability_cred(ba: Arc>) -> Response { - let mut ba_obj = ba.lock().unwrap(); - ba_obj.advance_days(85); // FOR TESTING ONLY - println!("Today's date according to server: {}", ba_obj.today()); - let enc_table = ba_obj.enc_bridge_table().clone(); +fn send_reachability_cred(context: LoxServerContext) -> Response { + context.advance_days_TEST(85); // FOR TESTING ONLY + let enc_table = context.encrypt_table(); let etable = EncBridgeTable { etable: enc_table }; let mut resp = Response::new(Body::from(serde_json::to_string(&etable).unwrap())); resp.headers_mut() @@ -185,113 +290,69 @@ fn send_reachability_cred(ba: Arc>) -> Response { resp } -fn send_keys(ba: Arc>) -> Response { - let ba_obj = ba.lock().unwrap(); - // vector of public keys (to serialize) - let ba_obj_pubkeys = vec![ - &ba_obj.lox_pub, - &ba_obj.migration_pub, - &ba_obj.migrationkey_pub, - &ba_obj.reachability_pub, - &ba_obj.invitation_pub, - ]; - println!("Today's date according to server: {}", ba_obj.today()); +fn send_keys(context: LoxServerContext) -> Response { + let pubkeys = context.pubkeys(); - let mut resp = Response::new(Body::from(serde_json::to_string(&ba_obj_pubkeys).unwrap())); + let mut resp = Response::new(Body::from(serde_json::to_string(&pubkeys).unwrap())); resp.headers_mut() .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp } -fn verify_and_send_open_cred(request: Bytes, ba: Arc>) -> Response { - let req: proto::open_invite::Request = serde_json::from_slice(&request).unwrap(); - let mut ba_obj = ba.lock().unwrap(); - let response = ba_obj.handle_open_invite(req).unwrap(); +fn verify_and_send_open_cred(request: Bytes, context: LoxServerContext) -> Response { + let req: open_invite::Request = serde_json::from_slice(&request).unwrap(); + let response = context.open_inv(req); let open_invite_resp_str = serde_json::to_string(&response).unwrap(); prepare_header(open_invite_resp_str) } -fn verify_and_send_trust_promo(request: Bytes, ba: Arc>) -> Response { - let req: proto::trust_promotion::Request = serde_json::from_slice(&request).unwrap(); - let mut ba_obj = ba.lock().unwrap(); - ba_obj.advance_days(31); // FOR TESTING ONLY - println!("Today's date according to server: {}", ba_obj.today()); - let response = ba_obj.handle_trust_promotion(req).unwrap(); +fn verify_and_send_trust_promo(request: Bytes, context: LoxServerContext) -> Response { + let req: trust_promotion::Request = serde_json::from_slice(&request).unwrap(); + context.advance_days_TEST(31); // FOR TESTING ONLY + let response = context.trust_promo(req); let trust_promo_resp_str = serde_json::to_string(&response).unwrap(); prepare_header(trust_promo_resp_str) } -fn verify_and_send_trust_migration(request: Bytes, ba: Arc>) -> Response { - let req: proto::migration::Request = serde_json::from_slice(&request).unwrap(); - let mut ba_obj = ba.lock().unwrap(); - let response = ba_obj.handle_migration(req).unwrap(); +fn verify_and_send_trust_migration(request: Bytes, context: LoxServerContext) -> Response { + let req: migration::Request = serde_json::from_slice(&request).unwrap(); + let response = context.trust_migration(req); let resp_str = serde_json::to_string(&response).unwrap(); prepare_header(resp_str) } -fn verify_and_send_level_up(request: Bytes, ba: Arc>) -> Response { - let req: proto::level_up::Request = serde_json::from_slice(&request).unwrap(); - let mut ba_obj = ba.lock().unwrap(); - let response = ba_obj.handle_level_up(req).unwrap(); +fn verify_and_send_level_up(request: Bytes, context: LoxServerContext) -> Response { + let req: level_up::Request = serde_json::from_slice(&request).unwrap(); + let response = context.level_up(req); let level_up_resp_str = serde_json::to_string(&response).unwrap(); prepare_header(level_up_resp_str) } -fn verify_and_send_issue_invite(request: Bytes, ba: Arc>) -> Response { - let req: proto::issue_invite::Request = serde_json::from_slice(&request).unwrap(); - let mut ba_obj = ba.lock().unwrap(); - let response = ba_obj.handle_issue_invite(req).unwrap(); +fn verify_and_send_issue_invite(request: Bytes, context: LoxServerContext) -> Response { + let req: issue_invite::Request = serde_json::from_slice(&request).unwrap(); + let response = context.issue_invite(req); let issue_invite_resp_str = serde_json::to_string(&response).unwrap(); prepare_header(issue_invite_resp_str) } -fn verify_and_send_redeem_invite(request: Bytes, ba: Arc>) -> Response { - let req: proto::redeem_invite::Request = serde_json::from_slice(&request).unwrap(); - let mut ba_obj = ba.lock().unwrap(); - let response = ba_obj.handle_redeem_invite(req).unwrap(); +fn verify_and_send_redeem_invite(request: Bytes, context: LoxServerContext) -> Response { + let req: redeem_invite::Request = serde_json::from_slice(&request).unwrap(); + let response = context.redeem_invite(req); let redeem_invite_resp_str = serde_json::to_string(&response).unwrap(); prepare_header(redeem_invite_resp_str) } -fn verify_and_send_check_blockage( - request: Bytes, - ba: Arc>, - db: Arc>, -) -> Response { - let req: proto::check_blockage::Request = serde_json::from_slice(&request).unwrap(); - let mut ba_obj = ba.lock().unwrap(); - // Created 5 buckets initially, so we will add 5 hot spares (for migration) and - // block all of the existing buckets to trigger migration table propagation - // FOR TESTING ONLY, ADD 5 NEW Buckets - for _ in 0..5 { - let bucket = [random(), random(), random()]; - ba_obj.add_spare_bucket(bucket); - } - ba_obj.enc_bridge_table(); +fn verify_and_send_check_blockage(request: Bytes, context: LoxServerContext) -> Response { + let req: check_blockage::Request = serde_json::from_slice(&request).unwrap(); - // FOR TESTING ONLY, BLOCK ALL BRIDGES - let mut db_obj = db.lock().unwrap(); - for index in 0..5 { - let b0 = ba_obj.bridge_table.buckets[index][0]; - let b1 = ba_obj.bridge_table.buckets[index][1]; - let b2 = ba_obj.bridge_table.buckets[index][2]; - ba_obj.bridge_unreachable(&b0, &mut db_obj); - ba_obj.bridge_unreachable(&b1, &mut db_obj); - ba_obj.bridge_unreachable(&b2, &mut db_obj); - } - ba_obj.enc_bridge_table(); - let response = ba_obj.handle_check_blockage(req).unwrap(); + let response = context.check_blockage(req); let check_blockage_resp_str = serde_json::to_string(&response).unwrap(); prepare_header(check_blockage_resp_str) } -fn verify_and_send_blockage_migration( - request: Bytes, - ba: Arc>, -) -> Response { - let req: proto::blockage_migration::Request = serde_json::from_slice(&request).unwrap(); - let mut ba_obj = ba.lock().unwrap(); - let response = ba_obj.handle_blockage_migration(req).unwrap(); +fn verify_and_send_blockage_migration(request: Bytes, context: LoxServerContext) -> Response { + let req: blockage_migration::Request = serde_json::from_slice(&request).unwrap(); + let response = context.blockage_migration(req); let resp_str = serde_json::to_string(&response).unwrap(); prepare_header(resp_str) } @@ -309,8 +370,32 @@ async fn shutdown_signal() { .expect("failed to listen for ctrl+c signal"); } -// Initial bridgedb setup then: -// Listen for updates and return new bridges to be added to the bridged +async fn rdsys_sender(rstream: ResourceStream, tx: Sender) { + for diff in rstream { + println!("Received diff: {:?}", diff); //send this through a channel + tx.send(diff).await.unwrap(); + sleep(Duration::from_secs(1)).await; + } +} + +async fn parse_bridges(rdsys_tx: Sender, rx: Receiver) { + loop { + let resourcediff = rx.recv().await.unwrap(); + let cmd = Command::Rdsys { resourcediff: resourcediff, }; + rdsys_tx.send(cmd).await.unwrap(); + } + +} + +#[derive(Debug)] +enum Command { + Rdsys { + resourcediff: ResourceDiff, + }, + Request { + request: Request, + } +} // Run with cargo run -- config.json #[tokio::main(worker_threads = 2)] @@ -321,6 +406,10 @@ async fn main() { // Read the JSON contents of the file as a ResourceInfo let rtype: ResourceInfo = serde_json::from_reader(reader).unwrap(); +let (rdsys_tx, mut context_rx) = mpsc::channel(32); +let request_tx = rdsys_tx.clone(); + + let context_manager = spawn(async move { // pass in distribution of open invite vs. hot spare buckets? let bridgedb = BridgeDb::new(); let lox_auth = BridgeAuth::new(bridgedb.pubkey); @@ -329,141 +418,131 @@ async fn main() { db: Arc::new(Mutex::new(bridgedb)), ba: Arc::new(Mutex::new(lox_auth)), }; - //Sender is resource stream and receiver is bridgedb function (add_openinv_bridges) - let (tx, rx) = async_channel::bounded(3); - // to populate the bridge db - let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) - .await - .unwrap(); - spawn(async move { - for diff in rstream { - println!("Received diff: {:?}", diff); //send this through a channel - tx.send(diff).await.expect("can not add to bridgedb)") - } - }); - let context_clone = context.clone(); - let _ = spawn(async move { - while let resourcediff = rx.recv().await.unwrap() { - // spawn(async move { - for new_resource in resourcediff.new { - for pt in new_resource { - println!("A NEW RESOURCE: {:?}", pt); - let mut bucket = [ - BridgeLine::default(), - BridgeLine::default(), - BridgeLine::default(), - ]; - let mut count = 0; - for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()].copy_from_slice(resource.address.as_bytes()); - let infostr: String = format!( - "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", - resource.r#type, - resource.blocked_in, - resource.protocol, - resource.fingerprint, - resource.or_addresses, - resource.distribution, - resource.flags, - resource.params, - ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; + while let Some(cmd) = context_rx.recv().await { + use Command::*; - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - info: info_bytes, - }; - - println!("Now it's a bridgeline: {:?}", bridgeline); - if count < 2 { - bucket[count] = bridgeline; - count += 1; - } else { - let mut ba_obj = context_clone.ba.lock().unwrap(); - let mut db_obj = context_clone.db.lock().unwrap(); - ba_obj.add_openinv_bridges(bucket, &mut db_obj); - count = 0; - bucket = [ + match cmd { + Rdsys {resourcediff} => { + for new_resource in resourcediff.new { + for pt in new_resource { + println!("A NEW RESOURCE: {:?}", pt); + let mut bucket = [ BridgeLine::default(), BridgeLine::default(), BridgeLine::default(), ]; + let mut count = 0; + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()] + .copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( + "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", + resource.r#type, + resource.blocked_in, + resource.protocol, + resource.fingerprint, + resource.or_addresses, + resource.distribution, + resource.flags, + resource.params, + ); + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; + + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; + + println!("Now it's a bridgeline: {:?}", bridgeline); + if count < 2 { + bucket[count] = bridgeline; + count += 1; + } else { + context.add_openinv_bucket(bucket); + count = 0; + bucket = [ + BridgeLine::default(), + BridgeLine::default(), + BridgeLine::default(), + ]; + } + } } } - } - } - for changed_resource in resourcediff.changed { - println!("A NEW CHANGED RESOURCE: {:?}", changed_resource); - } - for gone_resource in resourcediff.gone { - for pt in gone_resource { - println!("A NEW GONE RESOURCE: {:?}", pt); - let mut unreachable_bridge = BridgeLine::default(); - for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()].copy_from_slice(resource.address.as_bytes()); - let infostr: String = format!( - "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", - resource.r#type, - resource.blocked_in, - resource.protocol, - resource.fingerprint, - resource.or_addresses, - resource.distribution, - resource.flags, - resource.params, - ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; - - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - info: info_bytes, - }; - - println!("Now it's a bridgeline: {:?}", bridgeline); - let mut ba_obj = context_clone.ba.lock().unwrap(); - let mut db_obj = context_clone.db.lock().unwrap(); - ba_obj.bridge_unreachable(&unreachable_bridge, &mut db_obj); + for changed_resource in resourcediff.changed { + println!("A NEW CHANGED RESOURCE: {:?}", changed_resource); } + for gone_resource in resourcediff.gone { + for pt in gone_resource { + println!("A NEW GONE RESOURCE: {:?}", pt); + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()] + .copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( + "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", + resource.r#type, + resource.blocked_in, + resource.protocol, + resource.fingerprint, + resource.or_addresses, + resource.distribution, + resource.flags, + resource.params, + ); + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; + + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; + + println!("Now it's a bridgeline: {:?}", bridgeline); + context.add_unreachable(bridgeline); + } + } + } + context.encrypt_table(); } + Request {request} => { + } - // Create the encrypted bridge table - let mut ba_obj = context_clone.ba.lock().unwrap(); - ba_obj.enc_bridge_table(); } +} + }); - // let new_bridgedb = task::spawn(load_bridges()); - // Create and initialize a new db and lox_auth - // Make 3 x num_buckets open invitation bridges, in sets of 3 -/* for _ in 0..num_buckets { - let bucket = [random(), random(), random()]; - lox_auth.add_openinv_bridges(bucket, &mut bridgedb); - } -*/ + //Sender is resource stream and receiver is bridgedb function (add_openinv_bridges) + let (tx, mut rx) = async_channel::unbounded(); + // to populate the bridge db + let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) + .await + .unwrap(); + let rdsys_sender_handle = spawn(async {rdsys_sender(rstream, tx).await }); + let bridge_parser = spawn( async {parse_bridges(rdsys_tx, rx).await}); + future::join_all([rdsys_sender_handle, bridge_parser]).await; +/* let new_service = make_service_fn(move |_conn: &AddrStream| { - let context = context.clone(); - let service = service_fn(move |req| { - handle(context.clone(), req) - }); + let service = service_fn(move |req| handle(context, req)); async move { Ok::<_, Infallible>(service) } }); let addr = SocketAddr::from(([127, 0, 0, 1], 8001)); - let server = Server::bind(&addr).serve(new_service); - let graceful = server.with_graceful_shutdown(shutdown_signal()); +// let server = Server::bind(&addr).serve(new_service); +// let graceful = server.with_graceful_shutdown(shutdown_signal()); println!("Listening on {}", addr); if let Err(e) = graceful.await { eprintln!("server error: {}", e); } +*/ } From 3b0c8ab5b63325fae3b23724c7d7daa8e43c8876 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Tue, 14 Mar 2023 23:23:40 -0400 Subject: [PATCH 23/39] Implements server functionality, next get thread working --- crates/lox-distributor/src/main.rs | 238 +++++++++++++++-------------- 1 file changed, 127 insertions(+), 111 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index b861b9c..cff7343 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -1,9 +1,10 @@ -use async_channel::{Sender, Receiver}; +use async_channel::{Receiver, Sender}; use futures::future; use hyper::{ body, body::Bytes, header::HeaderValue, + http::response, server::conn::AddrStream, service::{make_service_fn, service_fn}, Body, Method, Request, Response, Server, StatusCode, @@ -32,7 +33,7 @@ use std::{ use serde_json; use serde_with::serde_as; -use tokio::{spawn, time::sleep, sync::mpsc}; +use tokio::{spawn, sync::{mpsc, oneshot}, time::sleep}; #[serde_as] #[derive(Serialize, Deserialize)] @@ -208,9 +209,9 @@ impl LoxServerContext { } } + async fn handle( - context: LoxServerContext, - // addr: SocketAddr, + cloned_context: LoxServerContext, req: Request, ) -> Result, Infallible> { println!("Request: {:?}", req); @@ -223,41 +224,41 @@ async fn handle( .body(Body::from("Allow POST")) .unwrap()), _ => match (req.method(), req.uri().path()) { - (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(context)), - (&Method::GET, "/reachability") => Ok::<_, Infallible>(send_reachability_cred(context)), - (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(context)), + (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(cloned_context)), + (&Method::GET, "/reachability") => Ok::<_, Infallible>(send_reachability_cred(cloned_context)), + (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(cloned_context)), (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_open_cred(bytes, context) + verify_and_send_open_cred(bytes, cloned_context) }), (&Method::POST, "/trustpromo") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_trust_promo(bytes, context) + verify_and_send_trust_promo(bytes, cloned_context) }), (&Method::POST, "/trustmig") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_trust_migration(bytes, context) + verify_and_send_trust_migration(bytes, cloned_context) }), (&Method::POST, "/levelup") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_level_up(bytes, context) + verify_and_send_level_up(bytes, cloned_context) }), (&Method::POST, "/issueinvite") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_issue_invite(bytes, context) + verify_and_send_issue_invite(bytes, cloned_context) }), (&Method::POST, "/redeem") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_redeem_invite(bytes, context) + verify_and_send_redeem_invite(bytes, cloned_context) }), (&Method::POST, "/checkblockage") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); // TEST ONLY: Block all existing bridges and add new ones for migration - verify_and_send_check_blockage(bytes, context) + verify_and_send_check_blockage(bytes, cloned_context) }), (&Method::POST, "/blockagemigration") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_blockage_migration(bytes, context) + verify_and_send_blockage_migration(bytes, cloned_context) }), _ => { // Return 404 not found response. @@ -378,27 +379,27 @@ async fn rdsys_sender(rstream: ResourceStream, tx: Sender) { } } -async fn parse_bridges(rdsys_tx: Sender, rx: Receiver) { +async fn parse_bridges(rdsys_tx: mpsc::Sender, rx: Receiver) { loop { let resourcediff = rx.recv().await.unwrap(); - let cmd = Command::Rdsys { resourcediff: resourcediff, }; + let cmd = Command::Rdsys { + resourcediff: resourcediff, + }; rdsys_tx.send(cmd).await.unwrap(); } - } #[derive(Debug)] enum Command { - Rdsys { - resourcediff: ResourceDiff, - }, + Rdsys { resourcediff: ResourceDiff }, Request { - request: Request, - } + req: Request, + sender: oneshot::Sender, Infallible>>, + }, } // Run with cargo run -- config.json -#[tokio::main(worker_threads = 2)] +#[tokio::main] async fn main() { let args: Vec = env::args().collect(); let file = File::open(&args[1]).expect("Should have been able to read config.json file"); @@ -406,38 +407,38 @@ async fn main() { // Read the JSON contents of the file as a ResourceInfo let rtype: ResourceInfo = serde_json::from_reader(reader).unwrap(); -let (rdsys_tx, mut context_rx) = mpsc::channel(32); -let request_tx = rdsys_tx.clone(); + let (rdsys_tx, mut context_rx) = mpsc::channel(32); + let mut request_tx = rdsys_tx.clone(); let context_manager = spawn(async move { - // pass in distribution of open invite vs. hot spare buckets? - let bridgedb = BridgeDb::new(); - let lox_auth = BridgeAuth::new(bridgedb.pubkey); + // pass in distribution of open invite vs. hot spare buckets? + let bridgedb = BridgeDb::new(); + let lox_auth = BridgeAuth::new(bridgedb.pubkey); - let context = LoxServerContext { - db: Arc::new(Mutex::new(bridgedb)), - ba: Arc::new(Mutex::new(lox_auth)), - }; + let context = LoxServerContext { + db: Arc::new(Mutex::new(bridgedb)), + ba: Arc::new(Mutex::new(lox_auth)), + }; - while let Some(cmd) = context_rx.recv().await { - use Command::*; + while let Some(cmd) = context_rx.recv().await { + use Command::*; - match cmd { - Rdsys {resourcediff} => { - for new_resource in resourcediff.new { - for pt in new_resource { - println!("A NEW RESOURCE: {:?}", pt); - let mut bucket = [ - BridgeLine::default(), - BridgeLine::default(), - BridgeLine::default(), - ]; - let mut count = 0; - for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()] - .copy_from_slice(resource.address.as_bytes()); - let infostr: String = format!( + match cmd { + Rdsys { resourcediff } => { + for new_resource in resourcediff.new { + for pt in new_resource { + println!("A NEW RESOURCE: {:?}", pt); + let mut bucket = [ + BridgeLine::default(), + BridgeLine::default(), + BridgeLine::default(), + ]; + let mut count = 0; + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()] + .copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", resource.r#type, resource.blocked_in, @@ -448,42 +449,43 @@ let request_tx = rdsys_tx.clone(); resource.flags, resource.params, ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; - - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - info: info_bytes, - }; - - println!("Now it's a bridgeline: {:?}", bridgeline); - if count < 2 { - bucket[count] = bridgeline; - count += 1; - } else { - context.add_openinv_bucket(bucket); - count = 0; - bucket = [ - BridgeLine::default(), - BridgeLine::default(), - BridgeLine::default(), - ]; + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = + [0; BRIDGE_BYTES - 18]; + + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; + + println!("Now it's a bridgeline: {:?}", bridgeline); + if count < 2 { + bucket[count] = bridgeline; + count += 1; + } else { + context.add_openinv_bucket(bucket); + count = 0; + bucket = [ + BridgeLine::default(), + BridgeLine::default(), + BridgeLine::default(), + ]; + } } } } - } - for changed_resource in resourcediff.changed { - println!("A NEW CHANGED RESOURCE: {:?}", changed_resource); - } - for gone_resource in resourcediff.gone { - for pt in gone_resource { - println!("A NEW GONE RESOURCE: {:?}", pt); - for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()] - .copy_from_slice(resource.address.as_bytes()); - let infostr: String = format!( + for changed_resource in resourcediff.changed { + println!("A NEW CHANGED RESOURCE: {:?}", changed_resource); + } + for gone_resource in resourcediff.gone { + for pt in gone_resource { + println!("A NEW GONE RESOURCE: {:?}", pt); + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()] + .copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", resource.r#type, resource.blocked_in, @@ -494,28 +496,29 @@ let request_tx = rdsys_tx.clone(); resource.flags, resource.params, ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; - - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - info: info_bytes, - }; - - println!("Now it's a bridgeline: {:?}", bridgeline); - context.add_unreachable(bridgeline); + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = + [0; BRIDGE_BYTES - 18]; + + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; + + println!("Now it's a bridgeline: {:?}", bridgeline); + context.add_unreachable(bridgeline); + } } } + context.encrypt_table(); + } + Request { req, sender } => { + let response = handle(context.clone(), req).await; + sender.send(response); } - context.encrypt_table(); } - Request {request} => { - } - } -} - }); //Sender is resource stream and receiver is bridgedb function (add_openinv_bridges) @@ -524,25 +527,38 @@ let request_tx = rdsys_tx.clone(); let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) .await .unwrap(); - let rdsys_sender_handle = spawn(async {rdsys_sender(rstream, tx).await }); + let rdsys_stream_handler = spawn(async { rdsys_sender(rstream, tx).await }); - let bridge_parser = spawn( async {parse_bridges(rdsys_tx, rx).await}); + let rdsys_resource_receiver = spawn(async { parse_bridges(rdsys_tx, rx).await }); - future::join_all([rdsys_sender_handle, bridge_parser]).await; -/* - let new_service = make_service_fn(move |_conn: &AddrStream| { - let service = service_fn(move |req| handle(context, req)); + let make_service = make_service_fn(|_conn: &AddrStream| { + let request_tx = request_tx.clone(); + let service = service_fn( move |req| { + let request_tx = request_tx.clone(); + let (response_tx, response_rx) = oneshot::channel(); + let cmd = Command::Request { + req: req, + sender: response_tx, + }; + async move { + request_tx.send(cmd).await.unwrap(); + response_rx.await.unwrap() + } + }); async move { Ok::<_, Infallible>(service) } }); let addr = SocketAddr::from(([127, 0, 0, 1], 8001)); -// let server = Server::bind(&addr).serve(new_service); -// let graceful = server.with_graceful_shutdown(shutdown_signal()); + let server = Server::bind(&addr).serve(make_service); + let graceful = server.with_graceful_shutdown(shutdown_signal()); println!("Listening on {}", addr); - if let Err(e) = graceful.await { eprintln!("server error: {}", e); } -*/ + + future::join_all([rdsys_stream_handler, rdsys_resource_receiver]).await; + } + + From c74da3a07883ba345a6e2bb1e84fa1461c30066e Mon Sep 17 00:00:00 2001 From: onyinyang Date: Wed, 15 Mar 2023 15:21:03 -0400 Subject: [PATCH 24/39] Server responds to requests and processes bridgelines from rdsys --- crates/lox-distributor/src/main.rs | 55 +++++++++++++++++------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index cff7343..cf879d8 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -4,7 +4,6 @@ use hyper::{ body, body::Bytes, header::HeaderValue, - http::response, server::conn::AddrStream, service::{make_service_fn, service_fn}, Body, Method, Request, Response, Server, StatusCode, @@ -33,7 +32,11 @@ use std::{ use serde_json; use serde_with::serde_as; -use tokio::{spawn, sync::{mpsc, oneshot}, time::sleep}; +use tokio::{ + spawn, + sync::{mpsc, oneshot}, + time::sleep, task::yield_now, +}; #[serde_as] #[derive(Serialize, Deserialize)] @@ -209,7 +212,6 @@ impl LoxServerContext { } } - async fn handle( cloned_context: LoxServerContext, req: Request, @@ -225,7 +227,9 @@ async fn handle( .unwrap()), _ => match (req.method(), req.uri().path()) { (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(cloned_context)), - (&Method::GET, "/reachability") => Ok::<_, Infallible>(send_reachability_cred(cloned_context)), + (&Method::GET, "/reachability") => { + Ok::<_, Infallible>(send_reachability_cred(cloned_context)) + } (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(cloned_context)), (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); @@ -386,16 +390,19 @@ async fn parse_bridges(rdsys_tx: mpsc::Sender, rx: Receiver, - sender: oneshot::Sender, Infallible>>, - }, + sender: oneshot::Sender, Infallible>>, + }, } // Run with cargo run -- config.json @@ -408,7 +415,7 @@ async fn main() { let rtype: ResourceInfo = serde_json::from_reader(reader).unwrap(); let (rdsys_tx, mut context_rx) = mpsc::channel(32); - let mut request_tx = rdsys_tx.clone(); + let request_tx = rdsys_tx.clone(); let context_manager = spawn(async move { // pass in distribution of open invite vs. hot spare buckets? @@ -512,17 +519,21 @@ async fn main() { } } context.encrypt_table(); + sleep(Duration::from_millis(1)).await; } Request { req, sender } => { let response = handle(context.clone(), req).await; - sender.send(response); + if let Err(e) = sender.send(response) { + eprintln!("Server Response Error: {:?}", e); + }; + sleep(Duration::from_millis(1)).await; } } } }); //Sender is resource stream and receiver is bridgedb function (add_openinv_bridges) - let (tx, mut rx) = async_channel::unbounded(); + let (tx, rx) = async_channel::unbounded(); // to populate the bridge db let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) .await @@ -531,10 +542,9 @@ async fn main() { let rdsys_resource_receiver = spawn(async { parse_bridges(rdsys_tx, rx).await }); - - let make_service = make_service_fn(|_conn: &AddrStream| { + let make_service = make_service_fn(move |_conn: &AddrStream| { let request_tx = request_tx.clone(); - let service = service_fn( move |req| { + let service = service_fn(move |req| { let request_tx = request_tx.clone(); let (response_tx, response_rx) = oneshot::channel(); let cmd = Command::Request { @@ -542,8 +552,8 @@ async fn main() { sender: response_tx, }; async move { - request_tx.send(cmd).await.unwrap(); - response_rx.await.unwrap() + request_tx.send(cmd).await.unwrap(); + response_rx.await.unwrap() } }); async move { Ok::<_, Infallible>(service) } @@ -551,14 +561,11 @@ async fn main() { let addr = SocketAddr::from(([127, 0, 0, 1], 8001)); let server = Server::bind(&addr).serve(make_service); - let graceful = server.with_graceful_shutdown(shutdown_signal()); - println!("Listening on {}", addr); - if let Err(e) = graceful.await { - eprintln!("server error: {}", e); - } - - future::join_all([rdsys_stream_handler, rdsys_resource_receiver]).await; + let graceful = server.with_graceful_shutdown(shutdown_signal()); + println!("Listening on {}", addr); + if let Err(e) = graceful.await { + eprintln!("server error: {}", e); + } + future::join_all([rdsys_stream_handler, rdsys_resource_receiver, context_manager]).await; } - - From 9616b95b5d861ac8553ab3d03d11b54050eabab8 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Wed, 15 Mar 2023 15:42:04 -0400 Subject: [PATCH 25/39] Update README --- crates/lox-distributor/README.md | 36 ++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/crates/lox-distributor/README.md b/crates/lox-distributor/README.md index 3783e31..cbfe60f 100644 --- a/crates/lox-distributor/README.md +++ b/crates/lox-distributor/README.md @@ -1,3 +1,35 @@ -# Lox server +# Lox Distributor -Simply run `cargo run` :) +The Lox distributor receives resources from [rdsys](https://gitlab.torproject.org/tpo/anti-censorship/rdsys) and writes them to [Lox +BridgeLines](https://git-crysp.uwaterloo.ca/iang/lox/src/master/src/bridge_table.rs#L42). Concurrently, it receives and responds to requests from [Lox clients](https://gitlab.torproject.org/tpo/anti-censorship/lox/lox-wasm). + +## Configure rdsys stream + +A test `config.json` is included for testing on a local instance of rdsys. This +can be edited to correspond to the desired types of resources and endpoints. + +## Test Run + +For testing purposes, you will need a running instance of rdsys as well as a running Lox client. + +### Run rdsys locally + +First clone rdsys from [here](https://gitlab.torproject.org/tpo/anti-censorship/rdsys) then change into the backend directory: + +``` +cd rdsys/cmd/backend +``` + +Finally run rdsys: + +``` + ./backend --config config.json +``` + +### Run Lox Distributor locally + +Simply run `cargo run -- config.json` :) + +### Run a Lox client locally + +First clone lox-wasm from [here](https://gitlab.torproject.org/tpo/anti-censorship/lox/lox-wasm). Follow the instructions in the [README](https://gitlab.torproject.org/tpo/anti-censorship/lox/lox-wasm/-/blob/main/README.md) to build and test the Lox client. From 9e78a905411dbfe2081274971f4bef5e737f74d7 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Fri, 17 Mar 2023 10:41:32 -0400 Subject: [PATCH 26/39] Adds graceful shutdown for all tasks, rdsys stream inconsistent shutdown --- crates/lox-distributor/src/main.rs | 310 +++++++++++++++++------------ 1 file changed, 182 insertions(+), 128 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index cf879d8..6998e04 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -18,7 +18,7 @@ use lox::{ }; use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; -use rdsys_backend::{proto::ResourceDiff, start_stream, ResourceStream}; +use rdsys_backend::{proto::ResourceDiff, start_stream}; use serde::{Deserialize, Serialize}; use std::{ convert::Infallible, @@ -29,13 +29,12 @@ use std::{ sync::{Arc, Mutex}, time::Duration, }; - use serde_json; use serde_with::serde_as; use tokio::{ spawn, - sync::{mpsc, oneshot}, - time::sleep, task::yield_now, + sync::{broadcast, mpsc, oneshot}, + time::sleep, signal, }; #[serde_as] @@ -373,9 +372,21 @@ async fn shutdown_signal() { tokio::signal::ctrl_c() .await .expect("failed to listen for ctrl+c signal"); + println!("Shut down Lox Server"); } -async fn rdsys_sender(rstream: ResourceStream, tx: Sender) { +async fn rdsys_stream(rtype: ResourceInfo, tx: Sender, mut kill: broadcast::Receiver<()>) { + tokio:: select! { + start_rdsys_stream = rdsys_sender(rtype, tx) => start_rdsys_stream , + _ = kill.recv() => {println!("Shut down rdsys stream"); return}, + } +} + +async fn rdsys_sender(rtype: ResourceInfo, tx: Sender) { + let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) + .await + .expect("rdsys stream initialization failed. Start rdsys or check config.json"); + sleep(Duration::from_millis(1)).await; for diff in rstream { println!("Received diff: {:?}", diff); //send this through a channel tx.send(diff).await.unwrap(); @@ -383,6 +394,13 @@ async fn rdsys_sender(rstream: ResourceStream, tx: Sender) { } } +async fn rdsys_bridge_parser(rdsys_tx: mpsc::Sender, rx: Receiver, mut kill: broadcast::Receiver<()>) { + tokio:: select! { + start_bridge_parser = parse_bridges(rdsys_tx, rx) => start_bridge_parser , + _ = kill.recv() => {println!("Shut down bridge_parser"); return}, + } +} + async fn parse_bridges(rdsys_tx: mpsc::Sender, rx: Receiver) { loop { let resourcediff = rx.recv().await.unwrap(); @@ -394,6 +412,131 @@ async fn parse_bridges(rdsys_tx: mpsc::Sender, rx: Receiver, mut kill: broadcast::Receiver<()>) { + tokio:: select! { + create_context = context_manager(context_rx) => create_context, + _ = kill.recv() => {println!("Shut down context_manager"); return}, + } +} + +async fn context_manager(mut context_rx: mpsc::Receiver) { + // pass in distribution of open invite vs. hot spare buckets? + + let bridgedb = BridgeDb::new(); + let lox_auth = BridgeAuth::new(bridgedb.pubkey); + + let context = LoxServerContext { + db: Arc::new(Mutex::new(bridgedb)), + ba: Arc::new(Mutex::new(lox_auth)), + }; + + while let Some(cmd) = context_rx.recv().await { + use Command::*; + + match cmd { + Rdsys { resourcediff } => { + for new_resource in resourcediff.new { + for pt in new_resource { + println!("A NEW RESOURCE: {:?}", pt); + let mut bucket = [ + BridgeLine::default(), + BridgeLine::default(), + BridgeLine::default(), + ]; + let mut count = 0; + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()] + .copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( + "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", + resource.r#type, + resource.blocked_in, + resource.protocol, + resource.fingerprint, + resource.or_addresses, + resource.distribution, + resource.flags, + resource.params, + ); + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = + [0; BRIDGE_BYTES - 18]; + + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; + + println!("Now it's a bridgeline: {:?}", bridgeline); + if count < 2 { + bucket[count] = bridgeline; + count += 1; + } else { + context.add_openinv_bucket(bucket); + count = 0; + bucket = [ + BridgeLine::default(), + BridgeLine::default(), + BridgeLine::default(), + ]; + } + } + } + } + for changed_resource in resourcediff.changed { + println!("A NEW CHANGED RESOURCE: {:?}", changed_resource); + } + for gone_resource in resourcediff.gone { + for pt in gone_resource { + println!("A NEW GONE RESOURCE: {:?}", pt); + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()] + .copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( + "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", + resource.r#type, + resource.blocked_in, + resource.protocol, + resource.fingerprint, + resource.or_addresses, + resource.distribution, + resource.flags, + resource.params, + ); + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = + [0; BRIDGE_BYTES - 18]; + + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; + + println!("Now it's a bridgeline: {:?}", bridgeline); + context.add_unreachable(bridgeline); + } + } + } + context.encrypt_table(); + sleep(Duration::from_millis(1)).await; + } + Request { req, sender } => { + let response = handle(context.clone(), req).await; + if let Err(e) = sender.send(response) { + eprintln!("Server Response Error: {:?}", e); + }; + sleep(Duration::from_millis(1)).await; + } + } + } + + +} + #[derive(Debug)] enum Command { Rdsys { @@ -405,7 +548,6 @@ enum Command { }, } -// Run with cargo run -- config.json #[tokio::main] async fn main() { let args: Vec = env::args().collect(); @@ -414,133 +556,38 @@ async fn main() { // Read the JSON contents of the file as a ResourceInfo let rtype: ResourceInfo = serde_json::from_reader(reader).unwrap(); - let (rdsys_tx, mut context_rx) = mpsc::channel(32); + let (rdsys_tx, context_rx) = mpsc::channel(32); let request_tx = rdsys_tx.clone(); - let context_manager = spawn(async move { - // pass in distribution of open invite vs. hot spare buckets? - let bridgedb = BridgeDb::new(); - let lox_auth = BridgeAuth::new(bridgedb.pubkey); - let context = LoxServerContext { - db: Arc::new(Mutex::new(bridgedb)), - ba: Arc::new(Mutex::new(lox_auth)), - }; - while let Some(cmd) = context_rx.recv().await { - use Command::*; + // create the shutdown broadcast channel + let (shutdown_tx, mut shutdown_rx) = broadcast::channel(16); + let kill_stream = shutdown_tx.subscribe(); + let kill_parser = shutdown_tx.subscribe(); + let kill_context= shutdown_tx.subscribe(); - match cmd { - Rdsys { resourcediff } => { - for new_resource in resourcediff.new { - for pt in new_resource { - println!("A NEW RESOURCE: {:?}", pt); - let mut bucket = [ - BridgeLine::default(), - BridgeLine::default(), - BridgeLine::default(), - ]; - let mut count = 0; - for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()] - .copy_from_slice(resource.address.as_bytes()); - let infostr: String = format!( - "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", - resource.r#type, - resource.blocked_in, - resource.protocol, - resource.fingerprint, - resource.or_addresses, - resource.distribution, - resource.flags, - resource.params, - ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = - [0; BRIDGE_BYTES - 18]; +// Listen for ctrl_c, send signal to broadcast shutdown to all threads by dropping shutdown_tx + let shutdown_handler = spawn(async move { + tokio::select! { + _ = signal::ctrl_c() => { + drop(shutdown_tx); + println!("Kill Sent, all threads should shutdown."); - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - info: info_bytes, - }; - - println!("Now it's a bridgeline: {:?}", bridgeline); - if count < 2 { - bucket[count] = bridgeline; - count += 1; - } else { - context.add_openinv_bucket(bucket); - count = 0; - bucket = [ - BridgeLine::default(), - BridgeLine::default(), - BridgeLine::default(), - ]; - } - } - } - } - for changed_resource in resourcediff.changed { - println!("A NEW CHANGED RESOURCE: {:?}", changed_resource); - } - for gone_resource in resourcediff.gone { - for pt in gone_resource { - println!("A NEW GONE RESOURCE: {:?}", pt); - for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()] - .copy_from_slice(resource.address.as_bytes()); - let infostr: String = format!( - "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", - resource.r#type, - resource.blocked_in, - resource.protocol, - resource.fingerprint, - resource.or_addresses, - resource.distribution, - resource.flags, - resource.params, - ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = - [0; BRIDGE_BYTES - 18]; - - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - info: info_bytes, - }; - - println!("Now it's a bridgeline: {:?}", bridgeline); - context.add_unreachable(bridgeline); - } - } - } - context.encrypt_table(); - sleep(Duration::from_millis(1)).await; - } - Request { req, sender } => { - let response = handle(context.clone(), req).await; - if let Err(e) = sender.send(response) { - eprintln!("Server Response Error: {:?}", e); - }; - sleep(Duration::from_millis(1)).await; - } + _ = shutdown_rx.recv().await; + println!("Receiving shutdown signals. . ."); } } - }); + }); + + + + let context_manager = spawn(async move { create_context_manager(context_rx, kill_context).await }); - //Sender is resource stream and receiver is bridgedb function (add_openinv_bridges) let (tx, rx) = async_channel::unbounded(); - // to populate the bridge db - let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) - .await - .unwrap(); - let rdsys_stream_handler = spawn(async { rdsys_sender(rstream, tx).await }); + let rdsys_stream_handler = spawn(async { rdsys_stream(rtype, tx, kill_stream).await }); - let rdsys_resource_receiver = spawn(async { parse_bridges(rdsys_tx, rx).await }); + let rdsys_resource_receiver = spawn(async { rdsys_bridge_parser(rdsys_tx, rx, kill_parser).await }); let make_service = make_service_fn(move |_conn: &AddrStream| { let request_tx = request_tx.clone(); @@ -561,11 +608,18 @@ async fn main() { let addr = SocketAddr::from(([127, 0, 0, 1], 8001)); let server = Server::bind(&addr).serve(make_service); - let graceful = server.with_graceful_shutdown(shutdown_signal()); - println!("Listening on {}", addr); - if let Err(e) = graceful.await { - eprintln!("server error: {}", e); - } - future::join_all([rdsys_stream_handler, rdsys_resource_receiver, context_manager]).await; + let graceful = server.with_graceful_shutdown(shutdown_signal()); + println!("Listening on {}", addr); + if let Err(e) = graceful.await { + eprintln!("server error: {}", e); + } + future::join_all([ + rdsys_stream_handler, + rdsys_resource_receiver, + context_manager, + shutdown_handler, + ]) + .await; + } From 0476a8841924c6d40420796ec26990b1bf9f35ec Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 20 Mar 2023 11:53:10 -0400 Subject: [PATCH 27/39] Add comments --- crates/lox-distributor/Cargo.toml | 1 - crates/lox-distributor/src/main.rs | 47 +++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index 03930ce..7b41d7f 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-channel = "1.8.0" base64 = "0.13" hyper = { version = "0.14.24", features = ["server"] } hex_fmt = "0.3" diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 6998e04..3e0834a 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -1,4 +1,3 @@ -use async_channel::{Receiver, Sender}; use futures::future; use hyper::{ body, @@ -211,6 +210,7 @@ impl LoxServerContext { } } +// Lox Request handling logic for each Lox request/protocol async fn handle( cloned_context: LoxServerContext, req: Request, @@ -274,6 +274,8 @@ async fn handle( } } + +// Generate and return an open invitation token fn generate_invite(context: LoxServerContext) -> Response { let invite = context.gen_invite(); let token = serde_json::to_string(&invite).unwrap(); @@ -294,6 +296,7 @@ fn send_reachability_cred(context: LoxServerContext) -> Response { resp } +// Return the serialized pubkeys for the Bridge Authority fn send_keys(context: LoxServerContext) -> Response { let pubkeys = context.pubkeys(); @@ -375,14 +378,17 @@ async fn shutdown_signal() { println!("Shut down Lox Server"); } -async fn rdsys_stream(rtype: ResourceInfo, tx: Sender, mut kill: broadcast::Receiver<()>) { +async fn rdsys_stream(rtype: ResourceInfo, tx: mpsc::Sender, mut kill: broadcast::Receiver<()>) { tokio:: select! { start_rdsys_stream = rdsys_sender(rtype, tx) => start_rdsys_stream , _ = kill.recv() => {println!("Shut down rdsys stream"); return}, } } -async fn rdsys_sender(rtype: ResourceInfo, tx: Sender) { +// Rdsys sender creates a ResourceStream with the api_endpoint, resource token and type specified +// in the config.json file. +// TODO: ensure this stream gracefully shutdowns on the ctrl_c command. +async fn rdsys_sender(rtype: ResourceInfo, tx: mpsc::Sender) { let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) .await .expect("rdsys stream initialization failed. Start rdsys or check config.json"); @@ -394,14 +400,16 @@ async fn rdsys_sender(rtype: ResourceInfo, tx: Sender) { } } -async fn rdsys_bridge_parser(rdsys_tx: mpsc::Sender, rx: Receiver, mut kill: broadcast::Receiver<()>) { +async fn rdsys_bridge_parser(rdsys_tx: mpsc::Sender, rx: mpsc::Receiver, mut kill: broadcast::Receiver<()>) { tokio:: select! { start_bridge_parser = parse_bridges(rdsys_tx, rx) => start_bridge_parser , _ = kill.recv() => {println!("Shut down bridge_parser"); return}, } } -async fn parse_bridges(rdsys_tx: mpsc::Sender, rx: Receiver) { +// Parse Bridges receives a ResourceDiff from rdsys_sender and sends it to the +// Context Manager to be parsed and added to the BridgeDB +async fn parse_bridges(rdsys_tx: mpsc::Sender, mut rx: mpsc::Receiver) { loop { let resourcediff = rx.recv().await.unwrap(); let cmd = Command::Rdsys { @@ -419,8 +427,10 @@ async fn create_context_manager(context_rx: mpsc::Receiver, mut kill: b } } +// Context Manager handles the Lox BridgeDB and Bridge Authority, ensuring +// that the DB can be updated from the rdsys stream and client requests +// can be responded to with an updated BridgeDB state async fn context_manager(mut context_rx: mpsc::Receiver) { - // pass in distribution of open invite vs. hot spare buckets? let bridgedb = BridgeDb::new(); let lox_auth = BridgeAuth::new(bridgedb.pubkey); @@ -531,12 +541,18 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { }; sleep(Duration::from_millis(1)).await; } + Shutdown { shutdown_sig} => { + println!("Sending Shutdown Signal, all threads should shutdown."); + drop(shutdown_sig); + println!("Shutdown Sent."); + } } } } +// Each of the commands that the Context Manager handles #[derive(Debug)] enum Command { Rdsys { @@ -546,6 +562,9 @@ enum Command { req: Request, sender: oneshot::Sender, Infallible>>, }, + Shutdown { + shutdown_sig: broadcast::Sender<()>, + } } #[tokio::main] @@ -554,14 +573,15 @@ async fn main() { let file = File::open(&args[1]).expect("Should have been able to read config.json file"); let reader = BufReader::new(file); // Read the JSON contents of the file as a ResourceInfo - let rtype: ResourceInfo = serde_json::from_reader(reader).unwrap(); + let rtype: ResourceInfo = serde_json::from_reader(reader).expect("Reading ResourceInfo from JSON failed."); let (rdsys_tx, context_rx) = mpsc::channel(32); let request_tx = rdsys_tx.clone(); + let shutdown_cmd_tx = rdsys_tx.clone(); - // create the shutdown broadcast channel + // create the shutdown broadcast channel and clone for every thread let (shutdown_tx, mut shutdown_rx) = broadcast::channel(16); let kill_stream = shutdown_tx.subscribe(); let kill_parser = shutdown_tx.subscribe(); @@ -571,20 +591,21 @@ async fn main() { let shutdown_handler = spawn(async move { tokio::select! { _ = signal::ctrl_c() => { - drop(shutdown_tx); - println!("Kill Sent, all threads should shutdown."); + let cmd = Command::Shutdown { + shutdown_sig: shutdown_tx, + }; + shutdown_cmd_tx.send(cmd).await.unwrap(); + sleep(Duration::from_secs(1)).await; _ = shutdown_rx.recv().await; - println!("Receiving shutdown signals. . ."); } } }); - let context_manager = spawn(async move { create_context_manager(context_rx, kill_context).await }); - let (tx, rx) = async_channel::unbounded(); + let (tx, rx) = mpsc::channel(32); let rdsys_stream_handler = spawn(async { rdsys_stream(rtype, tx, kill_stream).await }); let rdsys_resource_receiver = spawn(async { rdsys_bridge_parser(rdsys_tx, rx, kill_parser).await }); From 490ce2f19c83d34ff0f302a11e51a31efc78640c Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 20 Mar 2023 12:42:40 -0400 Subject: [PATCH 28/39] Add distributor logic for bridge updates from rdsys, handling for unsuccessful removals/updates --- crates/lox-distributor/src/main.rs | 295 +++++++++++++++++------------ 1 file changed, 174 insertions(+), 121 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 3e0834a..4013bf1 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -19,6 +19,8 @@ use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; use rdsys_backend::{proto::ResourceDiff, start_stream}; use serde::{Deserialize, Serialize}; +use serde_json; +use serde_with::serde_as; use std::{ convert::Infallible, env, @@ -28,12 +30,10 @@ use std::{ sync::{Arc, Mutex}, time::Duration, }; -use serde_json; -use serde_with::serde_as; use tokio::{ - spawn, + signal, spawn, sync::{broadcast, mpsc, oneshot}, - time::sleep, signal, + time::sleep, }; #[serde_as] @@ -113,10 +113,16 @@ impl LoxServerContext { ba_obj.add_openinv_bridges(bucket, &mut db_obj); } - fn add_unreachable(&self, bridgeline: BridgeLine) { + fn add_unreachable(&self, bridgeline: BridgeLine) -> bool { let mut ba_obj = self.ba.lock().unwrap(); let mut db_obj = self.db.lock().unwrap(); - ba_obj.bridge_unreachable(&bridgeline, &mut db_obj); + ba_obj.bridge_unreachable(&bridgeline, &mut db_obj) + } + + fn update_bridge(&self, bridgeline: BridgeLine) -> bool { + let mut ba_obj = self.ba.lock().unwrap(); + let mut db_obj = self.db.lock().unwrap(); + ba_obj.bridge_update(&bridgeline, &mut db_obj) } fn advance_days_TEST(&self, num: u16) { @@ -274,7 +280,6 @@ async fn handle( } } - // Generate and return an open invitation token fn generate_invite(context: LoxServerContext) -> Response { let invite = context.gen_invite(); @@ -378,8 +383,12 @@ async fn shutdown_signal() { println!("Shut down Lox Server"); } -async fn rdsys_stream(rtype: ResourceInfo, tx: mpsc::Sender, mut kill: broadcast::Receiver<()>) { - tokio:: select! { +async fn rdsys_stream( + rtype: ResourceInfo, + tx: mpsc::Sender, + mut kill: broadcast::Receiver<()>, +) { + tokio::select! { start_rdsys_stream = rdsys_sender(rtype, tx) => start_rdsys_stream , _ = kill.recv() => {println!("Shut down rdsys stream"); return}, } @@ -389,10 +398,10 @@ async fn rdsys_stream(rtype: ResourceInfo, tx: mpsc::Sender, mut // in the config.json file. // TODO: ensure this stream gracefully shutdowns on the ctrl_c command. async fn rdsys_sender(rtype: ResourceInfo, tx: mpsc::Sender) { - let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) + let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) .await .expect("rdsys stream initialization failed. Start rdsys or check config.json"); - sleep(Duration::from_millis(1)).await; + sleep(Duration::from_millis(1)).await; for diff in rstream { println!("Received diff: {:?}", diff); //send this through a channel tx.send(diff).await.unwrap(); @@ -400,8 +409,12 @@ async fn rdsys_sender(rtype: ResourceInfo, tx: mpsc::Sender) { } } -async fn rdsys_bridge_parser(rdsys_tx: mpsc::Sender, rx: mpsc::Receiver, mut kill: broadcast::Receiver<()>) { - tokio:: select! { +async fn rdsys_bridge_parser( + rdsys_tx: mpsc::Sender, + rx: mpsc::Receiver, + mut kill: broadcast::Receiver<()>, +) { + tokio::select! { start_bridge_parser = parse_bridges(rdsys_tx, rx) => start_bridge_parser , _ = kill.recv() => {println!("Shut down bridge_parser"); return}, } @@ -420,8 +433,11 @@ async fn parse_bridges(rdsys_tx: mpsc::Sender, mut rx: mpsc::Receiver, mut kill: broadcast::Receiver<()>) { - tokio:: select! { +async fn create_context_manager( + context_rx: mpsc::Receiver, + mut kill: broadcast::Receiver<()>, +) { + tokio::select! { create_context = context_manager(context_rx) => create_context, _ = kill.recv() => {println!("Shut down context_manager"); return}, } @@ -431,34 +447,33 @@ async fn create_context_manager(context_rx: mpsc::Receiver, mut kill: b // that the DB can be updated from the rdsys stream and client requests // can be responded to with an updated BridgeDB state async fn context_manager(mut context_rx: mpsc::Receiver) { + let bridgedb = BridgeDb::new(); + let lox_auth = BridgeAuth::new(bridgedb.pubkey); - let bridgedb = BridgeDb::new(); - let lox_auth = BridgeAuth::new(bridgedb.pubkey); + let context = LoxServerContext { + db: Arc::new(Mutex::new(bridgedb)), + ba: Arc::new(Mutex::new(lox_auth)), + }; - let context = LoxServerContext { - db: Arc::new(Mutex::new(bridgedb)), - ba: Arc::new(Mutex::new(lox_auth)), - }; + while let Some(cmd) = context_rx.recv().await { + use Command::*; - while let Some(cmd) = context_rx.recv().await { - use Command::*; - - match cmd { - Rdsys { resourcediff } => { - for new_resource in resourcediff.new { - for pt in new_resource { - println!("A NEW RESOURCE: {:?}", pt); - let mut bucket = [ - BridgeLine::default(), - BridgeLine::default(), - BridgeLine::default(), - ]; - let mut count = 0; - for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()] - .copy_from_slice(resource.address.as_bytes()); - let infostr: String = format!( + match cmd { + Rdsys { resourcediff } => { + for new_resource in resourcediff.new { + for pt in new_resource { + println!("A NEW RESOURCE: {:?}", pt); + let mut bucket = [ + BridgeLine::default(), + BridgeLine::default(), + BridgeLine::default(), + ]; + let mut count = 0; + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()] + .copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", resource.r#type, resource.blocked_in, @@ -469,43 +484,77 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { resource.flags, resource.params, ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = - [0; BRIDGE_BYTES - 18]; + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - info: info_bytes, - }; + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; - println!("Now it's a bridgeline: {:?}", bridgeline); - if count < 2 { - bucket[count] = bridgeline; - count += 1; - } else { - context.add_openinv_bucket(bucket); - count = 0; - bucket = [ - BridgeLine::default(), - BridgeLine::default(), - BridgeLine::default(), - ]; - } - } - } - } - for changed_resource in resourcediff.changed { - println!("A NEW CHANGED RESOURCE: {:?}", changed_resource); - } - for gone_resource in resourcediff.gone { - for pt in gone_resource { - println!("A NEW GONE RESOURCE: {:?}", pt); - for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()] - .copy_from_slice(resource.address.as_bytes()); - let infostr: String = format!( + println!("Now it's a bridgeline: {:?}", bridgeline); + if count < 2 { + bucket[count] = bridgeline; + count += 1; + } else { + context.add_openinv_bucket(bucket); + count = 0; + bucket = [ + BridgeLine::default(), + BridgeLine::default(), + BridgeLine::default(), + ]; + } + } + } + } + for changed_resource in resourcediff.changed { + for pt in changed_resource { + println!("A NEW CHANGED RESOURCE: {:?}", pt); + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()] + .copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( + "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", + resource.r#type, + resource.blocked_in, + resource.protocol, + resource.fingerprint, + resource.or_addresses, + resource.distribution, + resource.flags, + resource.params, + ); + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; + + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; + + println!("BridgeLine to be changed: {:?}", bridgeline); + let res = context.update_bridge(bridgeline); + if res { + println!("BridgeLine successfully updated: {:?}", bridgeline); + } else { + println!("'Changed' BridgeLine NOT UPDATED!! : {:?}", bridgeline); + //TODO probably do something else here + } + } + } + } + for gone_resource in resourcediff.gone { + for pt in gone_resource { + println!("A NEW GONE RESOURCE: {:?}", pt); + for resource in pt.1 { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()] + .copy_from_slice(resource.address.as_bytes()); + let infostr: String = format!( "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", resource.r#type, resource.blocked_in, @@ -516,40 +565,46 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { resource.flags, resource.params, ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = - [0; BRIDGE_BYTES - 18]; + let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - info: info_bytes, - }; + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + let bridgeline = BridgeLine { + addr: ip_bytes, + port: resource.port, + info: info_bytes, + }; - println!("Now it's a bridgeline: {:?}", bridgeline); - context.add_unreachable(bridgeline); - } - } - } - context.encrypt_table(); - sleep(Duration::from_millis(1)).await; - } - Request { req, sender } => { - let response = handle(context.clone(), req).await; - if let Err(e) = sender.send(response) { - eprintln!("Server Response Error: {:?}", e); - }; - sleep(Duration::from_millis(1)).await; - } - Shutdown { shutdown_sig} => { + println!("BridgeLine to be removed: {:?}", bridgeline); + let res = context.add_unreachable(bridgeline); + if res { + println!( + "BridgeLine successfully marked unreachable: {:?}", + bridgeline + ); + } else { + println!("'Gone' BridgeLine NOT REMOVED!! : {:?}", bridgeline); + //TODO probably do something else here + } + } + } + } + context.encrypt_table(); + sleep(Duration::from_millis(1)).await; + } + Request { req, sender } => { + let response = handle(context.clone(), req).await; + if let Err(e) = sender.send(response) { + eprintln!("Server Response Error: {:?}", e); + }; + sleep(Duration::from_millis(1)).await; + } + Shutdown { shutdown_sig } => { println!("Sending Shutdown Signal, all threads should shutdown."); drop(shutdown_sig); println!("Shutdown Sent."); - } - } - } - - + } + } + } } // Each of the commands that the Context Manager handles @@ -564,7 +619,7 @@ enum Command { }, Shutdown { shutdown_sig: broadcast::Sender<()>, - } + }, } #[tokio::main] @@ -573,22 +628,21 @@ async fn main() { let file = File::open(&args[1]).expect("Should have been able to read config.json file"); let reader = BufReader::new(file); // Read the JSON contents of the file as a ResourceInfo - let rtype: ResourceInfo = serde_json::from_reader(reader).expect("Reading ResourceInfo from JSON failed."); + let rtype: ResourceInfo = + serde_json::from_reader(reader).expect("Reading ResourceInfo from JSON failed."); let (rdsys_tx, context_rx) = mpsc::channel(32); let request_tx = rdsys_tx.clone(); let shutdown_cmd_tx = rdsys_tx.clone(); - - // create the shutdown broadcast channel and clone for every thread - let (shutdown_tx, mut shutdown_rx) = broadcast::channel(16); - let kill_stream = shutdown_tx.subscribe(); - let kill_parser = shutdown_tx.subscribe(); - let kill_context= shutdown_tx.subscribe(); + let (shutdown_tx, mut shutdown_rx) = broadcast::channel(16); + let kill_stream = shutdown_tx.subscribe(); + let kill_parser = shutdown_tx.subscribe(); + let kill_context = shutdown_tx.subscribe(); -// Listen for ctrl_c, send signal to broadcast shutdown to all threads by dropping shutdown_tx - let shutdown_handler = spawn(async move { + // Listen for ctrl_c, send signal to broadcast shutdown to all threads by dropping shutdown_tx + let shutdown_handler = spawn(async move { tokio::select! { _ = signal::ctrl_c() => { let cmd = Command::Shutdown { @@ -600,15 +654,16 @@ async fn main() { _ = shutdown_rx.recv().await; } } - }); + }); - - let context_manager = spawn(async move { create_context_manager(context_rx, kill_context).await }); + let context_manager = + spawn(async move { create_context_manager(context_rx, kill_context).await }); let (tx, rx) = mpsc::channel(32); let rdsys_stream_handler = spawn(async { rdsys_stream(rtype, tx, kill_stream).await }); - let rdsys_resource_receiver = spawn(async { rdsys_bridge_parser(rdsys_tx, rx, kill_parser).await }); + let rdsys_resource_receiver = + spawn(async { rdsys_bridge_parser(rdsys_tx, rx, kill_parser).await }); let make_service = make_service_fn(move |_conn: &AddrStream| { let request_tx = request_tx.clone(); @@ -634,13 +689,11 @@ async fn main() { if let Err(e) = graceful.await { eprintln!("server error: {}", e); } - future::join_all([ + future::join_all([ rdsys_stream_handler, rdsys_resource_receiver, context_manager, shutdown_handler, ]) .await; - - } From 3f5d497573fe8d27c2633b305842a09d3220603c Mon Sep 17 00:00:00 2001 From: onyinyang Date: Wed, 22 Mar 2023 19:14:56 -0400 Subject: [PATCH 29/39] Incorporate impl Stream for ResourceStream changes from rdsys-api-backend --- crates/lox-distributor/src/main.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 4013bf1..e528e81 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -1,4 +1,5 @@ use futures::future; +use futures::StreamExt; use hyper::{ body, body::Bytes, @@ -30,6 +31,7 @@ use std::{ sync::{Arc, Mutex}, time::Duration, }; + use tokio::{ signal, spawn, sync::{broadcast, mpsc, oneshot}, @@ -398,11 +400,11 @@ async fn rdsys_stream( // in the config.json file. // TODO: ensure this stream gracefully shutdowns on the ctrl_c command. async fn rdsys_sender(rtype: ResourceInfo, tx: mpsc::Sender) { - let rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) + let mut rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) .await .expect("rdsys stream initialization failed. Start rdsys or check config.json"); sleep(Duration::from_millis(1)).await; - for diff in rstream { + while let Some(diff) = rstream.next().await { println!("Received diff: {:?}", diff); //send this through a channel tx.send(diff).await.unwrap(); sleep(Duration::from_secs(1)).await; From 22ef5d157d459d4c5e2e808ebcfa0b285b73084a Mon Sep 17 00:00:00 2001 From: onyinyang Date: Fri, 24 Mar 2023 11:31:01 -0400 Subject: [PATCH 30/39] Updating bridges to make sense --- crates/lox-distributor/src/main.rs | 31 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index e528e81..ff43253 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -124,7 +124,7 @@ impl LoxServerContext { fn update_bridge(&self, bridgeline: BridgeLine) -> bool { let mut ba_obj = self.ba.lock().unwrap(); let mut db_obj = self.db.lock().unwrap(); - ba_obj.bridge_update(&bridgeline, &mut db_obj) + ba_obj.bridge_update(&bridgeline) } fn advance_days_TEST(&self, num: u16) { @@ -385,29 +385,28 @@ async fn shutdown_signal() { println!("Shut down Lox Server"); } +// Rdsys sender creates a ResourceStream with the api_endpoint, resource token and type specified +// in the config.json file. +// TODO: ensure this stream gracefully shutdowns on the ctrl_c command. async fn rdsys_stream( rtype: ResourceInfo, tx: mpsc::Sender, mut kill: broadcast::Receiver<()>, ) { - tokio::select! { - start_rdsys_stream = rdsys_sender(rtype, tx) => start_rdsys_stream , - _ = kill.recv() => {println!("Shut down rdsys stream"); return}, - } -} - -// Rdsys sender creates a ResourceStream with the api_endpoint, resource token and type specified -// in the config.json file. -// TODO: ensure this stream gracefully shutdowns on the ctrl_c command. -async fn rdsys_sender(rtype: ResourceInfo, tx: mpsc::Sender) { let mut rstream = start_stream(rtype.endpoint, rtype.name, rtype.token, rtype.types) .await .expect("rdsys stream initialization failed. Start rdsys or check config.json"); - sleep(Duration::from_millis(1)).await; - while let Some(diff) = rstream.next().await { - println!("Received diff: {:?}", diff); //send this through a channel - tx.send(diff).await.unwrap(); - sleep(Duration::from_secs(1)).await; + loop { + tokio::select! { + res = rstream.next() => { + match res { + Some(diff) => tx.send(diff).await.unwrap(), + None => return, + } + }, + _ = kill.recv() => {println!("Shut down rdsys stream"); return}, + + } } } From 562b74c274f51d1dce79182192a20e9b9fc973af Mon Sep 17 00:00:00 2001 From: onyinyang Date: Fri, 24 Mar 2023 13:16:26 -0400 Subject: [PATCH 31/39] Clean up code and improve readability --- crates/lox-distributor/src/main.rs | 48 +++++++++++------------------- 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index ff43253..91d3abb 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -20,7 +20,6 @@ use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; use rand::RngCore; use rdsys_backend::{proto::ResourceDiff, start_stream}; use serde::{Deserialize, Serialize}; -use serde_json; use serde_with::serde_as; use std::{ convert::Infallible, @@ -123,7 +122,6 @@ impl LoxServerContext { fn update_bridge(&self, bridgeline: BridgeLine) -> bool { let mut ba_obj = self.ba.lock().unwrap(); - let mut db_obj = self.db.lock().unwrap(); ba_obj.bridge_update(&bridgeline) } @@ -152,9 +150,9 @@ impl LoxServerContext { fn gen_invite(&self) -> Invite { let obj = self.db.lock().unwrap(); - return Invite { + Invite { invite: obj.invite(), - }; + } } fn open_inv(&self, req: open_invite::Request) -> open_invite::Response { @@ -233,11 +231,11 @@ async fn handle( .body(Body::from("Allow POST")) .unwrap()), _ => match (req.method(), req.uri().path()) { - (&Method::GET, "/invite") => Ok::<_, Infallible>(generate_invite(cloned_context)), - (&Method::GET, "/reachability") => { + (&Method::POST, "/invite") => Ok::<_, Infallible>(generate_invite(cloned_context)), + (&Method::POST, "/reachability") => { Ok::<_, Infallible>(send_reachability_cred(cloned_context)) } - (&Method::GET, "/pubkeys") => Ok::<_, Infallible>(send_keys(cloned_context)), + (&Method::POST, "/pubkeys") => Ok::<_, Infallible>(send_keys(cloned_context)), (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); verify_and_send_open_cred(bytes, cloned_context) @@ -286,10 +284,7 @@ async fn handle( fn generate_invite(context: LoxServerContext) -> Response { let invite = context.gen_invite(); let token = serde_json::to_string(&invite).unwrap(); - let mut resp = Response::new(Body::from(token)); - resp.headers_mut() - .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); - resp + prepare_header(token) } // Return the serialized encrypted bridge table @@ -297,20 +292,13 @@ fn send_reachability_cred(context: LoxServerContext) -> Response { context.advance_days_TEST(85); // FOR TESTING ONLY let enc_table = context.encrypt_table(); let etable = EncBridgeTable { etable: enc_table }; - let mut resp = Response::new(Body::from(serde_json::to_string(&etable).unwrap())); - resp.headers_mut() - .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); - resp + prepare_header(serde_json::to_string(&etable).unwrap()) } // Return the serialized pubkeys for the Bridge Authority fn send_keys(context: LoxServerContext) -> Response { let pubkeys = context.pubkeys(); - - let mut resp = Response::new(Body::from(serde_json::to_string(&pubkeys).unwrap())); - resp.headers_mut() - .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); - resp + prepare_header(serde_json::to_string(&pubkeys).unwrap()) } fn verify_and_send_open_cred(request: Bytes, context: LoxServerContext) -> Response { @@ -417,7 +405,7 @@ async fn rdsys_bridge_parser( ) { tokio::select! { start_bridge_parser = parse_bridges(rdsys_tx, rx) => start_bridge_parser , - _ = kill.recv() => {println!("Shut down bridge_parser"); return}, + _ = kill.recv() => {println!("Shut down bridge_parser");}, } } @@ -427,7 +415,7 @@ async fn parse_bridges(rdsys_tx: mpsc::Sender, mut rx: mpsc::Receiver create_context, - _ = kill.recv() => {println!("Shut down context_manager"); return}, + _ = kill.recv() => {println!("Shut down context_manager");}, } } @@ -461,8 +449,8 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { match cmd { Rdsys { resourcediff } => { - for new_resource in resourcediff.new { - for pt in new_resource { + if let Some(new_resources) = resourcediff.new { + for pt in new_resources { println!("A NEW RESOURCE: {:?}", pt); let mut bucket = [ BridgeLine::default(), @@ -510,8 +498,8 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { } } } - for changed_resource in resourcediff.changed { - for pt in changed_resource { + if let Some(changed_resources) = resourcediff.changed { + for pt in changed_resources { println!("A NEW CHANGED RESOURCE: {:?}", pt); for resource in pt.1 { let mut ip_bytes: [u8; 16] = [0; 16]; @@ -548,8 +536,8 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { } } } - for gone_resource in resourcediff.gone { - for pt in gone_resource { + if let Some(gone_resources) = resourcediff.gone { + for pt in gone_resources { println!("A NEW GONE RESOURCE: {:?}", pt); for resource in pt.1 { let mut ip_bytes: [u8; 16] = [0; 16]; @@ -672,7 +660,7 @@ async fn main() { let request_tx = request_tx.clone(); let (response_tx, response_rx) = oneshot::channel(); let cmd = Command::Request { - req: req, + req, sender: response_tx, }; async move { From d2bd91e0feb4b7030c9f2e52ce1768680c70fa64 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Tue, 4 Apr 2023 19:34:35 -0400 Subject: [PATCH 32/39] Update bridgeline sizes to match lox library --- crates/lox-distributor/Cargo.toml | 2 +- crates/lox-distributor/src/lox_context.rs | 277 ++++++++++++++++++ crates/lox-distributor/src/main.rs | 340 +++------------------- 3 files changed, 321 insertions(+), 298 deletions(-) create mode 100644 crates/lox-distributor/src/lox_context.rs diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index 7b41d7f..334f891 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -17,4 +17,4 @@ serde_with = "1.9.1" serde_json = "1.0.87" lox = { git = "https://gitlab.torproject.org/onyinyang/lox.git"} -rdsys_backend = { git = "https://gitlab.torproject.org/cohosh/rdsys-backend-api.git"} +rdsys_backend = { git = "https://gitlab.torproject.org/onyinyang/rdsys-backend-api.git"} diff --git a/crates/lox-distributor/src/lox_context.rs b/crates/lox-distributor/src/lox_context.rs new file mode 100644 index 0000000..212b754 --- /dev/null +++ b/crates/lox-distributor/src/lox_context.rs @@ -0,0 +1,277 @@ + +use hyper::{ + body::Bytes, + header::HeaderValue, + Body, Response, +}; + +use lox::{ + BridgeAuth, BridgeDb, OPENINV_LENGTH, + bridge_table::{BridgeLine, ENC_BUCKET_BYTES}, + proto::{ + blockage_migration, check_blockage, issue_invite, level_up, migration, open_invite, + redeem_invite, trust_promotion, + }, + IssuerPubKey, +}; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +use std::{ + sync::{Arc, Mutex}, +}; + + +#[serde_as] +#[derive(Serialize, Deserialize)] +pub struct Invite { + #[serde_as(as = "[_; OPENINV_LENGTH]")] + invite: [u8; OPENINV_LENGTH], +} + +#[serde_as] +#[derive(Serialize, Deserialize)] +pub struct EncBridgeTable { + #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")] + etable: Vec<[u8; ENC_BUCKET_BYTES]>, +} + +/// Create a random BridgeLine for testing ONLY. Do not use in production! +/// This was copied directly from lox/src/bridge_table.rs in order +/// to easily initialize a bridgedb/lox_auth with structurally +/// correct buckets to be used for Lox requests/verifications/responses. +/// In production, existing bridges should be translated into this format +/// in a private function and sorted into buckets (3 bridges/bucket is suggested +/// but experience may suggest something else) in some intelligent way. + +pub fn random() -> BridgeLine { + let mut rng = rand::thread_rng(); + let mut res: BridgeLine = BridgeLine::default(); + // Pick a random 4-byte address + let mut addr: [u8; 4] = [0; 4]; + rng.fill_bytes(&mut addr); + // If the leading byte is 224 or more, that's not a valid IPv4 + // address. Choose an IPv6 address instead (but don't worry too + // much about it being well formed). + if addr[0] >= 224 { + rng.fill_bytes(&mut res.addr); + } else { + // Store an IPv4 address as a v4-mapped IPv6 address + res.addr[10] = 255; + res.addr[11] = 255; + res.addr[12..16].copy_from_slice(&addr); + }; + let ports: [u16; 4] = [443, 4433, 8080, 43079]; + let portidx = (rng.next_u32() % 4) as usize; + res.port = ports[portidx]; + res.uid_fingerprint = rng.next_u64(); + let mut cert: [u8; 52] = [0; 52]; + rng.fill_bytes(&mut cert); + let infostr: String = format!( + "obfs4 cert={}, iat-mode=0", + base64::encode_config(cert, base64::STANDARD_NO_PAD) + ); + res.info[..infostr.len()].copy_from_slice(infostr.as_bytes()); + res +} + +#[derive(Clone)] +pub struct LoxServerContext { + pub db: Arc>, + pub ba: Arc>, +} + +impl LoxServerContext { + pub fn add_openinv_bucket(&self, bucket: [BridgeLine; 3]) { + let mut ba_obj = self.ba.lock().unwrap(); + let mut db_obj = self.db.lock().unwrap(); + ba_obj.add_openinv_bridges(bucket, &mut db_obj); + } + + pub fn add_unreachable(&self, bridgeline: BridgeLine) -> bool { + let mut ba_obj = self.ba.lock().unwrap(); + let mut db_obj = self.db.lock().unwrap(); + ba_obj.bridge_unreachable(&bridgeline, &mut db_obj) + } + + pub fn update_bridge(&self, bridgeline: BridgeLine) -> bool { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.bridge_update(&bridgeline) + } + + fn advance_days_TEST(&self, num: u16) { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.advance_days(num); // FOR TESTING ONLY + println!("Today's date according to server: {}", ba_obj.today()); + } + + pub fn encrypt_table(&self) -> Vec<[u8; ENC_BUCKET_BYTES]> { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.enc_bridge_table().clone() + } + + fn pubkeys(&self) -> Vec { + let ba_obj = self.ba.lock().unwrap(); + // vector of public keys (to serialize) + vec![ + ba_obj.lox_pub.clone(), + ba_obj.migration_pub.clone(), + ba_obj.migrationkey_pub.clone(), + ba_obj.reachability_pub.clone(), + ba_obj.invitation_pub.clone(), + ] + } + + fn gen_invite(&self) -> Invite { + let obj = self.db.lock().unwrap(); + Invite { + invite: obj.invite(), + } + } + + fn open_inv(&self, req: open_invite::Request) -> open_invite::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_open_invite(req).unwrap() + } + + fn trust_promo(&self, req: trust_promotion::Request) -> trust_promotion::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_trust_promotion(req).unwrap() + } + + fn trust_migration(&self, req: migration::Request) -> migration::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_migration(req).unwrap() + } + + fn level_up(&self, req: level_up::Request) -> level_up::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_level_up(req).unwrap() + } + + fn issue_invite(&self, req: issue_invite::Request) -> issue_invite::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_issue_invite(req).unwrap() + } + + fn redeem_invite(&self, req: redeem_invite::Request) -> redeem_invite::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_redeem_invite(req).unwrap() + } + + fn check_blockage(&self, req: check_blockage::Request) -> check_blockage::Response { + let mut ba_obj = self.ba.lock().unwrap(); + // Created 5 buckets initially, so we will add 5 hot spares (for migration) and + // block all of the existing buckets to trigger migration table propagation + // FOR TESTING ONLY, ADD 5 NEW Buckets + for _ in 0..5 { + let bucket = [random(), random(), random()]; + ba_obj.add_spare_bucket(bucket); + } + ba_obj.enc_bridge_table(); + + // FOR TESTING ONLY, BLOCK ALL BRIDGES + let mut db_obj = self.db.lock().unwrap(); + for index in 0..5 { + let b0 = ba_obj.bridge_table.buckets[index][0]; + let b1 = ba_obj.bridge_table.buckets[index][1]; + let b2 = ba_obj.bridge_table.buckets[index][2]; + ba_obj.bridge_unreachable(&b0, &mut db_obj); + ba_obj.bridge_unreachable(&b1, &mut db_obj); + ba_obj.bridge_unreachable(&b2, &mut db_obj); + } + ba_obj.enc_bridge_table(); + ba_obj.handle_check_blockage(req).unwrap() + } + + fn blockage_migration(&self, req: blockage_migration::Request) -> blockage_migration::Response { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.handle_blockage_migration(req).unwrap() + } +} + +// Generate and return an open invitation token +pub fn generate_invite(context: LoxServerContext) -> Response { + let invite = context.gen_invite(); + let token = serde_json::to_string(&invite).unwrap(); + prepare_header(token) +} + +// Return the serialized encrypted bridge table +pub fn send_reachability_cred(context: LoxServerContext) -> Response { + context.advance_days_TEST(85); // FOR TESTING ONLY + let enc_table = context.encrypt_table(); + let etable = EncBridgeTable { etable: enc_table }; + prepare_header(serde_json::to_string(&etable).unwrap()) +} + +// Return the serialized pubkeys for the Bridge Authority +pub fn send_keys(context: LoxServerContext) -> Response { + let pubkeys = context.pubkeys(); + prepare_header(serde_json::to_string(&pubkeys).unwrap()) +} + +pub fn verify_and_send_open_cred(request: Bytes, context: LoxServerContext) -> Response { + let req: open_invite::Request = serde_json::from_slice(&request).unwrap(); + let response = context.open_inv(req); + let open_invite_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(open_invite_resp_str) +} + +pub fn verify_and_send_trust_promo(request: Bytes, context: LoxServerContext) -> Response { + let req: trust_promotion::Request = serde_json::from_slice(&request).unwrap(); + context.advance_days_TEST(31); // FOR TESTING ONLY + let response = context.trust_promo(req); + let trust_promo_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(trust_promo_resp_str) +} + +pub fn verify_and_send_trust_migration(request: Bytes, context: LoxServerContext) -> Response { + let req: migration::Request = serde_json::from_slice(&request).unwrap(); + let response = context.trust_migration(req); + let resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(resp_str) +} + +pub fn verify_and_send_level_up(request: Bytes, context: LoxServerContext) -> Response { + let req: level_up::Request = serde_json::from_slice(&request).unwrap(); + let response = context.level_up(req); + let level_up_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(level_up_resp_str) +} + +pub fn verify_and_send_issue_invite(request: Bytes, context: LoxServerContext) -> Response { + let req: issue_invite::Request = serde_json::from_slice(&request).unwrap(); + let response = context.issue_invite(req); + let issue_invite_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(issue_invite_resp_str) +} + +pub fn verify_and_send_redeem_invite(request: Bytes, context: LoxServerContext) -> Response { + let req: redeem_invite::Request = serde_json::from_slice(&request).unwrap(); + let response = context.redeem_invite(req); + let redeem_invite_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(redeem_invite_resp_str) +} + +pub fn verify_and_send_check_blockage(request: Bytes, context: LoxServerContext) -> Response { + let req: check_blockage::Request = serde_json::from_slice(&request).unwrap(); + + let response = context.check_blockage(req); + let check_blockage_resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(check_blockage_resp_str) +} + +pub fn verify_and_send_blockage_migration(request: Bytes, context: LoxServerContext) -> Response { + let req: blockage_migration::Request = serde_json::from_slice(&request).unwrap(); + let response = context.blockage_migration(req); + let resp_str = serde_json::to_string(&response).unwrap(); + prepare_header(resp_str) +} + +fn prepare_header(response: String) -> Response { + let mut resp = Response::new(Body::from(response)); + resp.headers_mut() + .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + resp +} \ No newline at end of file diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 91d3abb..5b66f61 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -2,25 +2,17 @@ use futures::future; use futures::StreamExt; use hyper::{ body, - body::Bytes, header::HeaderValue, server::conn::AddrStream, service::{make_service_fn, service_fn}, Body, Method, Request, Response, Server, StatusCode, }; -use lox::bridge_table::{BridgeLine, BRIDGE_BYTES, ENC_BUCKET_BYTES}; -use lox::{ - proto::{ - blockage_migration, check_blockage, issue_invite, level_up, migration, open_invite, - redeem_invite, trust_promotion, - }, - IssuerPubKey, -}; -use lox::{BridgeAuth, BridgeDb, OPENINV_LENGTH}; -use rand::RngCore; +use lox::bridge_table::{BridgeLine, BRIDGE_BYTES}; + +use lox::{BridgeAuth, BridgeDb}; + use rdsys_backend::{proto::ResourceDiff, start_stream}; -use serde::{Deserialize, Serialize}; -use serde_with::serde_as; +use serde::{Deserialize}; use std::{ convert::Infallible, env, @@ -31,191 +23,15 @@ use std::{ time::Duration, }; +mod lox_context; +use lox_context::LoxServerContext; + use tokio::{ signal, spawn, sync::{broadcast, mpsc, oneshot}, time::sleep, }; -#[serde_as] -#[derive(Serialize, Deserialize)] -pub struct Invite { - #[serde_as(as = "[_; OPENINV_LENGTH]")] - invite: [u8; OPENINV_LENGTH], -} - -#[serde_as] -#[derive(Serialize, Deserialize)] -pub struct EncBridgeTable { - #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")] - etable: Vec<[u8; ENC_BUCKET_BYTES]>, -} - -#[derive(Debug, Deserialize)] -struct ResourceInfo { - endpoint: String, - name: String, - token: String, - types: Vec, -} -// Populate Bridgedb from rdsys - -/// Create a random BridgeLine for testing ONLY. Do not use in production! -/// This was copied directly from lox/src/bridge_table.rs in order -/// to easily initialize a bridgedb/lox_auth with structurally -/// correct buckets to be used for Lox requests/verifications/responses. -/// In production, existing bridges should be translated into this format -/// in a private function and sorted into buckets (3 bridges/bucket is suggested -/// but experience may suggest something else) in some intelligent way. - -pub fn random() -> BridgeLine { - let mut rng = rand::thread_rng(); - let mut res: BridgeLine = BridgeLine::default(); - // Pick a random 4-byte address - let mut addr: [u8; 4] = [0; 4]; - rng.fill_bytes(&mut addr); - // If the leading byte is 224 or more, that's not a valid IPv4 - // address. Choose an IPv6 address instead (but don't worry too - // much about it being well formed). - if addr[0] >= 224 { - rng.fill_bytes(&mut res.addr); - } else { - // Store an IPv4 address as a v4-mapped IPv6 address - res.addr[10] = 255; - res.addr[11] = 255; - res.addr[12..16].copy_from_slice(&addr); - }; - let ports: [u16; 4] = [443, 4433, 8080, 43079]; - let portidx = (rng.next_u32() % 4) as usize; - res.port = ports[portidx]; - let mut fingerprint: [u8; 20] = [0; 20]; - let mut cert: [u8; 52] = [0; 52]; - rng.fill_bytes(&mut fingerprint); - rng.fill_bytes(&mut cert); - let infostr: String = format!( - "obfs4 {} cert={} iat-mode=0", - hex_fmt::HexFmt(fingerprint), - base64::encode_config(cert, base64::STANDARD_NO_PAD) - ); - res.info[..infostr.len()].copy_from_slice(infostr.as_bytes()); - res -} - -#[derive(Clone)] -struct LoxServerContext { - db: Arc>, - ba: Arc>, -} - -impl LoxServerContext { - fn add_openinv_bucket(&self, bucket: [BridgeLine; 3]) { - let mut ba_obj = self.ba.lock().unwrap(); - let mut db_obj = self.db.lock().unwrap(); - ba_obj.add_openinv_bridges(bucket, &mut db_obj); - } - - fn add_unreachable(&self, bridgeline: BridgeLine) -> bool { - let mut ba_obj = self.ba.lock().unwrap(); - let mut db_obj = self.db.lock().unwrap(); - ba_obj.bridge_unreachable(&bridgeline, &mut db_obj) - } - - fn update_bridge(&self, bridgeline: BridgeLine) -> bool { - let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.bridge_update(&bridgeline) - } - - fn advance_days_TEST(&self, num: u16) { - let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.advance_days(num); // FOR TESTING ONLY - println!("Today's date according to server: {}", ba_obj.today()); - } - - fn encrypt_table(&self) -> Vec<[u8; ENC_BUCKET_BYTES]> { - let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.enc_bridge_table().clone() - } - - fn pubkeys(&self) -> Vec { - let ba_obj = self.ba.lock().unwrap(); - // vector of public keys (to serialize) - vec![ - ba_obj.lox_pub.clone(), - ba_obj.migration_pub.clone(), - ba_obj.migrationkey_pub.clone(), - ba_obj.reachability_pub.clone(), - ba_obj.invitation_pub.clone(), - ] - } - - fn gen_invite(&self) -> Invite { - let obj = self.db.lock().unwrap(); - Invite { - invite: obj.invite(), - } - } - - fn open_inv(&self, req: open_invite::Request) -> open_invite::Response { - let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.handle_open_invite(req).unwrap() - } - - fn trust_promo(&self, req: trust_promotion::Request) -> trust_promotion::Response { - let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.handle_trust_promotion(req).unwrap() - } - - fn trust_migration(&self, req: migration::Request) -> migration::Response { - let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.handle_migration(req).unwrap() - } - - fn level_up(&self, req: level_up::Request) -> level_up::Response { - let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.handle_level_up(req).unwrap() - } - - fn issue_invite(&self, req: issue_invite::Request) -> issue_invite::Response { - let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.handle_issue_invite(req).unwrap() - } - - fn redeem_invite(&self, req: redeem_invite::Request) -> redeem_invite::Response { - let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.handle_redeem_invite(req).unwrap() - } - - fn check_blockage(&self, req: check_blockage::Request) -> check_blockage::Response { - let mut ba_obj = self.ba.lock().unwrap(); - // Created 5 buckets initially, so we will add 5 hot spares (for migration) and - // block all of the existing buckets to trigger migration table propagation - // FOR TESTING ONLY, ADD 5 NEW Buckets - for _ in 0..5 { - let bucket = [random(), random(), random()]; - ba_obj.add_spare_bucket(bucket); - } - ba_obj.enc_bridge_table(); - - // FOR TESTING ONLY, BLOCK ALL BRIDGES - let mut db_obj = self.db.lock().unwrap(); - for index in 0..5 { - let b0 = ba_obj.bridge_table.buckets[index][0]; - let b1 = ba_obj.bridge_table.buckets[index][1]; - let b2 = ba_obj.bridge_table.buckets[index][2]; - ba_obj.bridge_unreachable(&b0, &mut db_obj); - ba_obj.bridge_unreachable(&b1, &mut db_obj); - ba_obj.bridge_unreachable(&b2, &mut db_obj); - } - ba_obj.enc_bridge_table(); - ba_obj.handle_check_blockage(req).unwrap() - } - - fn blockage_migration(&self, req: blockage_migration::Request) -> blockage_migration::Response { - let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.handle_blockage_migration(req).unwrap() - } -} - // Lox Request handling logic for each Lox request/protocol async fn handle( cloned_context: LoxServerContext, @@ -231,43 +47,43 @@ async fn handle( .body(Body::from("Allow POST")) .unwrap()), _ => match (req.method(), req.uri().path()) { - (&Method::POST, "/invite") => Ok::<_, Infallible>(generate_invite(cloned_context)), + (&Method::POST, "/invite") => Ok::<_, Infallible>(lox_context::generate_invite(cloned_context)), (&Method::POST, "/reachability") => { - Ok::<_, Infallible>(send_reachability_cred(cloned_context)) + Ok::<_, Infallible>(lox_context::send_reachability_cred(cloned_context)) } - (&Method::POST, "/pubkeys") => Ok::<_, Infallible>(send_keys(cloned_context)), + (&Method::POST, "/pubkeys") => Ok::<_, Infallible>(lox_context::send_keys(cloned_context)), (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_open_cred(bytes, cloned_context) + lox_context::verify_and_send_open_cred(bytes, cloned_context) }), (&Method::POST, "/trustpromo") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_trust_promo(bytes, cloned_context) + lox_context::verify_and_send_trust_promo(bytes, cloned_context) }), (&Method::POST, "/trustmig") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_trust_migration(bytes, cloned_context) + lox_context::verify_and_send_trust_migration(bytes, cloned_context) }), (&Method::POST, "/levelup") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_level_up(bytes, cloned_context) + lox_context::verify_and_send_level_up(bytes, cloned_context) }), (&Method::POST, "/issueinvite") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_issue_invite(bytes, cloned_context) + lox_context::verify_and_send_issue_invite(bytes, cloned_context) }), (&Method::POST, "/redeem") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_redeem_invite(bytes, cloned_context) + lox_context::verify_and_send_redeem_invite(bytes, cloned_context) }), (&Method::POST, "/checkblockage") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); // TEST ONLY: Block all existing bridges and add new ones for migration - verify_and_send_check_blockage(bytes, cloned_context) + lox_context::verify_and_send_check_blockage(bytes, cloned_context) }), (&Method::POST, "/blockagemigration") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); - verify_and_send_blockage_migration(bytes, cloned_context) + lox_context::verify_and_send_blockage_migration(bytes, cloned_context) }), _ => { // Return 404 not found response. @@ -280,92 +96,6 @@ async fn handle( } } -// Generate and return an open invitation token -fn generate_invite(context: LoxServerContext) -> Response { - let invite = context.gen_invite(); - let token = serde_json::to_string(&invite).unwrap(); - prepare_header(token) -} - -// Return the serialized encrypted bridge table -fn send_reachability_cred(context: LoxServerContext) -> Response { - context.advance_days_TEST(85); // FOR TESTING ONLY - let enc_table = context.encrypt_table(); - let etable = EncBridgeTable { etable: enc_table }; - prepare_header(serde_json::to_string(&etable).unwrap()) -} - -// Return the serialized pubkeys for the Bridge Authority -fn send_keys(context: LoxServerContext) -> Response { - let pubkeys = context.pubkeys(); - prepare_header(serde_json::to_string(&pubkeys).unwrap()) -} - -fn verify_and_send_open_cred(request: Bytes, context: LoxServerContext) -> Response { - let req: open_invite::Request = serde_json::from_slice(&request).unwrap(); - let response = context.open_inv(req); - let open_invite_resp_str = serde_json::to_string(&response).unwrap(); - prepare_header(open_invite_resp_str) -} - -fn verify_and_send_trust_promo(request: Bytes, context: LoxServerContext) -> Response { - let req: trust_promotion::Request = serde_json::from_slice(&request).unwrap(); - context.advance_days_TEST(31); // FOR TESTING ONLY - let response = context.trust_promo(req); - let trust_promo_resp_str = serde_json::to_string(&response).unwrap(); - prepare_header(trust_promo_resp_str) -} - -fn verify_and_send_trust_migration(request: Bytes, context: LoxServerContext) -> Response { - let req: migration::Request = serde_json::from_slice(&request).unwrap(); - let response = context.trust_migration(req); - let resp_str = serde_json::to_string(&response).unwrap(); - prepare_header(resp_str) -} - -fn verify_and_send_level_up(request: Bytes, context: LoxServerContext) -> Response { - let req: level_up::Request = serde_json::from_slice(&request).unwrap(); - let response = context.level_up(req); - let level_up_resp_str = serde_json::to_string(&response).unwrap(); - prepare_header(level_up_resp_str) -} - -fn verify_and_send_issue_invite(request: Bytes, context: LoxServerContext) -> Response { - let req: issue_invite::Request = serde_json::from_slice(&request).unwrap(); - let response = context.issue_invite(req); - let issue_invite_resp_str = serde_json::to_string(&response).unwrap(); - prepare_header(issue_invite_resp_str) -} - -fn verify_and_send_redeem_invite(request: Bytes, context: LoxServerContext) -> Response { - let req: redeem_invite::Request = serde_json::from_slice(&request).unwrap(); - let response = context.redeem_invite(req); - let redeem_invite_resp_str = serde_json::to_string(&response).unwrap(); - prepare_header(redeem_invite_resp_str) -} - -fn verify_and_send_check_blockage(request: Bytes, context: LoxServerContext) -> Response { - let req: check_blockage::Request = serde_json::from_slice(&request).unwrap(); - - let response = context.check_blockage(req); - let check_blockage_resp_str = serde_json::to_string(&response).unwrap(); - prepare_header(check_blockage_resp_str) -} - -fn verify_and_send_blockage_migration(request: Bytes, context: LoxServerContext) -> Response { - let req: blockage_migration::Request = serde_json::from_slice(&request).unwrap(); - let response = context.blockage_migration(req); - let resp_str = serde_json::to_string(&response).unwrap(); - prepare_header(resp_str) -} - -fn prepare_header(response: String) -> Response { - let mut resp = Response::new(Body::from(response)); - resp.headers_mut() - .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); - resp -} - async fn shutdown_signal() { tokio::signal::ctrl_c() .await @@ -373,6 +103,16 @@ async fn shutdown_signal() { println!("Shut down Lox Server"); } + +#[derive(Debug, Deserialize)] +struct ResourceInfo { + endpoint: String, + name: String, + token: String, + types: Vec, +} +// Populate Bridgedb from rdsys + // Rdsys sender creates a ResourceStream with the api_endpoint, resource token and type specified // in the config.json file. // TODO: ensure this stream gracefully shutdowns on the ctrl_c command. @@ -439,7 +179,7 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { let bridgedb = BridgeDb::new(); let lox_auth = BridgeAuth::new(bridgedb.pubkey); - let context = LoxServerContext { + let context = lox_context::LoxServerContext { db: Arc::new(Mutex::new(bridgedb)), ba: Arc::new(Mutex::new(lox_auth)), }; @@ -459,11 +199,13 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { ]; let mut count = 0; for resource in pt.1 { + let test = resource.get_uid().unwrap(); let mut ip_bytes: [u8; 16] = [0; 16]; ip_bytes[..resource.address.len()] .copy_from_slice(resource.address.as_bytes()); + let resource_uid = resource.get_uid().expect("Unable to get Fingerprint UID of resource"); let infostr: String = format!( - "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", + "type={} blocked_in={:?} protocol={} fingerprint={:?} or_addresses={:?} distribution={} flags={:?} params={:?}", resource.r#type, resource.blocked_in, resource.protocol, @@ -473,15 +215,15 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { resource.flags, resource.params, ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; + let mut info_bytes: [u8; BRIDGE_BYTES - 26] = [0; BRIDGE_BYTES - 26]; info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); let bridgeline = BridgeLine { addr: ip_bytes, port: resource.port, + uid_fingerprint: resource_uid, info: info_bytes, }; - println!("Now it's a bridgeline: {:?}", bridgeline); if count < 2 { bucket[count] = bridgeline; @@ -505,8 +247,9 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { let mut ip_bytes: [u8; 16] = [0; 16]; ip_bytes[..resource.address.len()] .copy_from_slice(resource.address.as_bytes()); + let resource_uid = resource.get_uid().expect("Unable to get Fingerprint UID of resource"); let infostr: String = format!( - "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", + "type={} blocked_in={:?} protocol={} fingerprint= {:?} or_addresses={:?} distribution={} flags={:?} params={:?}", resource.r#type, resource.blocked_in, resource.protocol, @@ -516,12 +259,13 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { resource.flags, resource.params, ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; + let mut info_bytes: [u8; BRIDGE_BYTES - 26] = [0; BRIDGE_BYTES - 26]; info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); let bridgeline = BridgeLine { addr: ip_bytes, port: resource.port, + uid_fingerprint: resource_uid, info: info_bytes, }; @@ -543,8 +287,9 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { let mut ip_bytes: [u8; 16] = [0; 16]; ip_bytes[..resource.address.len()] .copy_from_slice(resource.address.as_bytes()); + let resource_uid = resource.get_uid().expect("Unable to get Fingerprint UID of resource"); let infostr: String = format!( - "type={} blocked_in={:?} protocol={} fingerprint={} or_addresses={:?} distribution={} flags={:?} params={:?}", + "type={} blocked_in={:?} protocol={} fingerprint={:?} or_addresses={:?} distribution={} flags={:?} params={:?}", resource.r#type, resource.blocked_in, resource.protocol, @@ -554,12 +299,13 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { resource.flags, resource.params, ); - let mut info_bytes: [u8; BRIDGE_BYTES - 18] = [0; BRIDGE_BYTES - 18]; + let mut info_bytes: [u8; BRIDGE_BYTES - 26] = [0; BRIDGE_BYTES - 26]; info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); let bridgeline = BridgeLine { addr: ip_bytes, port: resource.port, + uid_fingerprint: resource_uid, info: info_bytes, }; From 4695a1170241132194ce797770cf3e73ad46d06a Mon Sep 17 00:00:00 2001 From: onyinyang Date: Wed, 5 Apr 2023 16:26:23 -0400 Subject: [PATCH 33/39] Ensure that left over bridges (not grouped into a bucket) are properly handled --- crates/lox-distributor/src/lox_context.rs | 24 +++++++++++++++- crates/lox-distributor/src/main.rs | 35 +++++++++++++++++------ 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/crates/lox-distributor/src/lox_context.rs b/crates/lox-distributor/src/lox_context.rs index 212b754..802a5a5 100644 --- a/crates/lox-distributor/src/lox_context.rs +++ b/crates/lox-distributor/src/lox_context.rs @@ -7,7 +7,7 @@ use hyper::{ use lox::{ BridgeAuth, BridgeDb, OPENINV_LENGTH, - bridge_table::{BridgeLine, ENC_BUCKET_BYTES}, + bridge_table::{BridgeLine, ENC_BUCKET_BYTES, MAX_BRIDGES_PER_BUCKET}, proto::{ blockage_migration, check_blockage, issue_invite, level_up, migration, open_invite, redeem_invite, trust_promotion, @@ -79,15 +79,37 @@ pub fn random() -> BridgeLine { pub struct LoxServerContext { pub db: Arc>, pub ba: Arc>, + pub extra_bridges: Arc>>, } impl LoxServerContext { + + pub fn append_extra_bridges(&self, bridge: BridgeLine){ + let mut extra_bridges = self.extra_bridges.lock().unwrap(); + extra_bridges.push(bridge); + } + + pub fn remove_extra_bridges(&self) -> [BridgeLine; MAX_BRIDGES_PER_BUCKET] { + let mut extra_bridges = self.extra_bridges.lock().unwrap(); + [ + extra_bridges.remove(0), + extra_bridges.remove(1), + extra_bridges.remove(2), + ] + + } + pub fn add_openinv_bucket(&self, bucket: [BridgeLine; 3]) { let mut ba_obj = self.ba.lock().unwrap(); let mut db_obj = self.db.lock().unwrap(); ba_obj.add_openinv_bridges(bucket, &mut db_obj); } + pub fn add_spare_bucket(&self, bucket: [BridgeLine; 3]) { + let mut ba_obj = self.ba.lock().unwrap(); + ba_obj.add_spare_bucket(bucket); + } + pub fn add_unreachable(&self, bridgeline: BridgeLine) -> bool { let mut ba_obj = self.ba.lock().unwrap(); let mut db_obj = self.db.lock().unwrap(); diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 5b66f61..13d4e41 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -182,6 +182,7 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { let context = lox_context::LoxServerContext { db: Arc::new(Mutex::new(bridgedb)), ba: Arc::new(Mutex::new(lox_auth)), + extra_bridges: Arc::new(Mutex::new(Vec::new())), }; while let Some(cmd) = context_rx.recv().await { @@ -190,16 +191,15 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { match cmd { Rdsys { resourcediff } => { if let Some(new_resources) = resourcediff.new { + let mut count = 0; + let mut bucket = [ + BridgeLine::default(), + BridgeLine::default(), + BridgeLine::default(), + ]; for pt in new_resources { println!("A NEW RESOURCE: {:?}", pt); - let mut bucket = [ - BridgeLine::default(), - BridgeLine::default(), - BridgeLine::default(), - ]; - let mut count = 0; for resource in pt.1 { - let test = resource.get_uid().unwrap(); let mut ip_bytes: [u8; 16] = [0; 16]; ip_bytes[..resource.address.len()] .copy_from_slice(resource.address.as_bytes()); @@ -229,6 +229,8 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { bucket[count] = bridgeline; count += 1; } else { + // TODO: Decide the circumstances under which a bridge is allocated to an open_inv or spare bucket, + // eventually also do some more fancy grouping of new resources, i.e., by type or region context.add_openinv_bucket(bucket); count = 0; bucket = [ @@ -239,6 +241,17 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { } } } + // Handle the extra buckets that were not allocated already + if count != 0 { + for val in 0..count { + if context.extra_bridges.lock().unwrap().len() < 2 { + context.append_extra_bridges(bucket[val]); + } else { + bucket = context.remove_extra_bridges(); + context.add_spare_bucket(bucket); + } + } + } } if let Some(changed_resources) = resourcediff.changed { for pt in changed_resources { @@ -274,7 +287,13 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { if res { println!("BridgeLine successfully updated: {:?}", bridgeline); } else { - println!("'Changed' BridgeLine NOT UPDATED!! : {:?}", bridgeline); + println!("BridgeLine: {:?} not found in Lox's Bridgetable. Save it as a new resource for now!", bridgeline); + if context.extra_bridges.lock().unwrap().len() < 2 { + context.append_extra_bridges(bridgeline); + } else { + let bucket = context.remove_extra_bridges(); + context.add_spare_bucket(bucket); + } //TODO probably do something else here } } From 1adf14567114fcced91a9ae6ba130ea7d23fb2ef Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 10 Apr 2023 12:16:19 -0400 Subject: [PATCH 34/39] Make bucket size match constant in Lox library for all functions --- crates/lox-distributor/src/lox_context.rs | 11 ++++++----- crates/lox-distributor/src/main.rs | 17 +++++------------ 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/crates/lox-distributor/src/lox_context.rs b/crates/lox-distributor/src/lox_context.rs index 802a5a5..c04cef1 100644 --- a/crates/lox-distributor/src/lox_context.rs +++ b/crates/lox-distributor/src/lox_context.rs @@ -91,11 +91,12 @@ impl LoxServerContext { pub fn remove_extra_bridges(&self) -> [BridgeLine; MAX_BRIDGES_PER_BUCKET] { let mut extra_bridges = self.extra_bridges.lock().unwrap(); - [ - extra_bridges.remove(0), - extra_bridges.remove(1), - extra_bridges.remove(2), - ] + let mut return_bridges = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; + for i in 0..MAX_BRIDGES_PER_BUCKET{ + return_bridges[i] = extra_bridges.remove(i); + } + + return_bridges } diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 13d4e41..e3c5309 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -7,6 +7,7 @@ use hyper::{ service::{make_service_fn, service_fn}, Body, Method, Request, Response, Server, StatusCode, }; +use lox::bridge_table::MAX_BRIDGES_PER_BUCKET; use lox::bridge_table::{BridgeLine, BRIDGE_BYTES}; use lox::{BridgeAuth, BridgeDb}; @@ -192,11 +193,7 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { Rdsys { resourcediff } => { if let Some(new_resources) = resourcediff.new { let mut count = 0; - let mut bucket = [ - BridgeLine::default(), - BridgeLine::default(), - BridgeLine::default(), - ]; + let mut bucket= [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; for pt in new_resources { println!("A NEW RESOURCE: {:?}", pt); for resource in pt.1 { @@ -225,7 +222,7 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { info: info_bytes, }; println!("Now it's a bridgeline: {:?}", bridgeline); - if count < 2 { + if count < MAX_BRIDGES_PER_BUCKET-1 { bucket[count] = bridgeline; count += 1; } else { @@ -233,18 +230,14 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { // eventually also do some more fancy grouping of new resources, i.e., by type or region context.add_openinv_bucket(bucket); count = 0; - bucket = [ - BridgeLine::default(), - BridgeLine::default(), - BridgeLine::default(), - ]; + bucket = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; } } } // Handle the extra buckets that were not allocated already if count != 0 { for val in 0..count { - if context.extra_bridges.lock().unwrap().len() < 2 { + if context.extra_bridges.lock().unwrap().len() < (MAX_BRIDGES_PER_BUCKET-1) { context.append_extra_bridges(bucket[val]); } else { bucket = context.remove_extra_bridges(); From 292827fa63961d1c7fd907abae66c5404199014b Mon Sep 17 00:00:00 2001 From: onyinyang Date: Wed, 3 May 2023 20:11:10 -0400 Subject: [PATCH 35/39] Add handling of gone, not blocked, resources --- crates/lox-distributor/src/lox_context.rs | 9 +++++++++ crates/lox-distributor/src/main.rs | 22 +++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/lox-distributor/src/lox_context.rs b/crates/lox-distributor/src/lox_context.rs index c04cef1..bb4f351 100644 --- a/crates/lox-distributor/src/lox_context.rs +++ b/crates/lox-distributor/src/lox_context.rs @@ -111,6 +111,15 @@ impl LoxServerContext { ba_obj.add_spare_bucket(bucket); } + pub fn replace_with_new(&self, bridgeline: BridgeLine) -> bool { + let mut ba_obj = self.ba.lock().unwrap(); + let mut db_obj = self.db.lock().unwrap(); + let mut eb_obj = self.extra_bridges.lock().unwrap(); + let mut available_bridge = eb_obj.last(); + + ba_obj.bridge_replace(&bridgeline, available_bridge, &mut db_obj) + + } pub fn add_unreachable(&self, bridgeline: BridgeLine) -> bool { let mut ba_obj = self.ba.lock().unwrap(); let mut db_obj = self.db.lock().unwrap(); diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index e3c5309..a9aad1d 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -292,6 +292,12 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { } } } + // gone resources are not the same as blocked resources. + // Instead, these are bridges which have either failed to pass tests for some period + // or have expired bridge descriptors. In both cases, the bridge is unusable, but this + // is not likely due to censorship. Therefore, we replace gone resources with new resources + // TODO: create a notion of blocked resources from information collected through various means: + // https://gitlab.torproject.org/tpo/anti-censorship/censorship-analysis/-/issues/40035 if let Some(gone_resources) = resourcediff.gone { for pt in gone_resources { println!("A NEW GONE RESOURCE: {:?}", pt); @@ -320,7 +326,7 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { uid_fingerprint: resource_uid, info: info_bytes, }; - + /* // Marking bridges as unreachable is reserved for blocked bridges println!("BridgeLine to be removed: {:?}", bridgeline); let res = context.add_unreachable(bridgeline); if res { @@ -332,12 +338,26 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { println!("'Gone' BridgeLine NOT REMOVED!! : {:?}", bridgeline); //TODO probably do something else here } + */ + println!("BridgeLine to be replaced: {:?}", bridgeline); + let res = context.replace_with_new(bridgeline); + if res { + println!( + "BridgeLine successfully replaced: {:?}", + bridgeline + ); + } else { + println!("'Gone' BridgeLine NOT replaced, marked removed!! : {:?}", bridgeline); + //TODO probably do something else here + } + } } } context.encrypt_table(); sleep(Duration::from_millis(1)).await; } + Request { req, sender } => { let response = handle(context.clone(), req).await; if let Err(e) = sender.send(response) { From 13d1bc8b1dfeb6d2edd85df3919b46290c9502ba Mon Sep 17 00:00:00 2001 From: onyinyang Date: Mon, 8 May 2023 20:30:30 -0400 Subject: [PATCH 36/39] Add leftover bridges to bridgedb --- crates/lox-distributor/src/lox_context.rs | 9 +++++++++ crates/lox-distributor/src/main.rs | 1 + 2 files changed, 10 insertions(+) diff --git a/crates/lox-distributor/src/lox_context.rs b/crates/lox-distributor/src/lox_context.rs index bb4f351..6111aba 100644 --- a/crates/lox-distributor/src/lox_context.rs +++ b/crates/lox-distributor/src/lox_context.rs @@ -100,6 +100,15 @@ impl LoxServerContext { } + pub fn allocate_leftover_bridges(&self) { + let mut ba_obj = self.ba.lock().unwrap(); + let mut db_obj = self.db.lock().unwrap(); + let mut extra_bridges = self.extra_bridges.lock().unwrap(); + ba_obj.allocate_bridges(&mut extra_bridges, &mut db_obj); + + + } + pub fn add_openinv_bucket(&self, bucket: [BridgeLine; 3]) { let mut ba_obj = self.ba.lock().unwrap(); let mut db_obj = self.db.lock().unwrap(); diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index a9aad1d..07f8234 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -354,6 +354,7 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { } } } + context.allocate_leftover_bridges(); context.encrypt_table(); sleep(Duration::from_millis(1)).await; } From da4d7c962f150df17f2ab90622c79304be16ab5a Mon Sep 17 00:00:00 2001 From: onyinyang Date: Thu, 11 May 2023 11:07:42 -0400 Subject: [PATCH 37/39] Add fix for failure to replace bridges - Change text for disabled functionality for blocked bridges --- crates/lox-distributor/src/lox_context.rs | 6 +++ crates/lox-distributor/src/main.rs | 56 ++++++++++++++++------- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/crates/lox-distributor/src/lox_context.rs b/crates/lox-distributor/src/lox_context.rs index 6111aba..d79ac30 100644 --- a/crates/lox-distributor/src/lox_context.rs +++ b/crates/lox-distributor/src/lox_context.rs @@ -80,6 +80,7 @@ pub struct LoxServerContext { pub db: Arc>, pub ba: Arc>, pub extra_bridges: Arc>>, + pub unreplaced_bridges: Arc>>, } impl LoxServerContext { @@ -100,6 +101,11 @@ impl LoxServerContext { } + pub fn new_unreplaced_bridge(&self, bridge: BridgeLine) { + let mut unreplaced_bridges = self.unreplaced_bridges.lock().unwrap(); + unreplaced_bridges.push(bridge); + } + pub fn allocate_leftover_bridges(&self) { let mut ba_obj = self.ba.lock().unwrap(); let mut db_obj = self.db.lock().unwrap(); diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 07f8234..1dbd0bb 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -184,6 +184,7 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { db: Arc::new(Mutex::new(bridgedb)), ba: Arc::new(Mutex::new(lox_auth)), extra_bridges: Arc::new(Mutex::new(Vec::new())), + unreplaced_bridges: Arc::new(Mutex::new(Vec::new())), }; while let Some(cmd) = context_rx.recv().await { @@ -222,6 +223,21 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { info: info_bytes, }; println!("Now it's a bridgeline: {:?}", bridgeline); + if context.unreplaced_bridges.lock().unwrap().len() > 0 { + println!("BridgeLine to be replaced: {:?}", bridgeline); + let res = context.replace_with_new(bridgeline); + if res { + println!( + "BridgeLine successfully replaced: {:?}", + bridgeline + ); + } else { + // Add the bridge to the list of unreplaced bridges in the Lox context and try + // again to replace at the next update (nothing changes in the Lox Authority) + println!("'Gone' BridgeLine NOT replaced, saved for next update! : {:?}", bridgeline); + context.new_unreplaced_bridge(bridgeline); + } + } else { if count < MAX_BRIDGES_PER_BUCKET-1 { bucket[count] = bridgeline; count += 1; @@ -233,6 +249,7 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { bucket = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; } } + } } // Handle the extra buckets that were not allocated already if count != 0 { @@ -287,7 +304,7 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { let bucket = context.remove_extra_bridges(); context.add_spare_bucket(bucket); } - //TODO probably do something else here + } } } @@ -326,7 +343,27 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { uid_fingerprint: resource_uid, info: info_bytes, }; - /* // Marking bridges as unreachable is reserved for blocked bridges + println!("BridgeLine to be replaced: {:?}", bridgeline); + let res = context.replace_with_new(bridgeline); + if res { + println!( + "BridgeLine successfully replaced: {:?}", + bridgeline + ); + } else { + // Add the bridge to the list of unreplaced bridges in the Lox context and try + // again to replace at the next update (nothing changes in the Lox Authority) + println!("'Gone' BridgeLine NOT replaced, saved for next update! : {:?}", bridgeline); + context.new_unreplaced_bridge(bridgeline); + } + + } + } + } + /* Functionality for marking bridges as unreachable/blocked is currently not enabled as there is not + yet a reliable way to determine that a bridge is blocked. This means that migrations to unblocked bridges do not + currently work but can be easily enabled with a list of `blocked resources` from rdsys or another source with something + like the following: println!("BridgeLine to be removed: {:?}", bridgeline); let res = context.add_unreachable(bridgeline); if res { @@ -339,21 +376,6 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { //TODO probably do something else here } */ - println!("BridgeLine to be replaced: {:?}", bridgeline); - let res = context.replace_with_new(bridgeline); - if res { - println!( - "BridgeLine successfully replaced: {:?}", - bridgeline - ); - } else { - println!("'Gone' BridgeLine NOT replaced, marked removed!! : {:?}", bridgeline); - //TODO probably do something else here - } - - } - } - } context.allocate_leftover_bridges(); context.encrypt_table(); sleep(Duration::from_millis(1)).await; From 3e3f50c2153585f4f8ae7ed5162dcc4db97e73fd Mon Sep 17 00:00:00 2001 From: onyinyang Date: Thu, 11 May 2023 11:11:57 -0400 Subject: [PATCH 38/39] Refactors lox-distributor to make division of tasks clearer --- crates/lox-distributor/src/lox_context.rs | 37 ++-- crates/lox-distributor/src/main.rs | 207 +++--------------- crates/lox-distributor/src/request_handler.rs | 74 +++++++ crates/lox-distributor/src/resource_parser.rs | 30 +++ 4 files changed, 151 insertions(+), 197 deletions(-) create mode 100644 crates/lox-distributor/src/request_handler.rs create mode 100644 crates/lox-distributor/src/resource_parser.rs diff --git a/crates/lox-distributor/src/lox_context.rs b/crates/lox-distributor/src/lox_context.rs index d79ac30..c9993a0 100644 --- a/crates/lox-distributor/src/lox_context.rs +++ b/crates/lox-distributor/src/lox_context.rs @@ -1,26 +1,17 @@ - -use hyper::{ - body::Bytes, - header::HeaderValue, - Body, Response, -}; +use hyper::{body::Bytes, header::HeaderValue, Body, Response}; use lox::{ - BridgeAuth, BridgeDb, OPENINV_LENGTH, bridge_table::{BridgeLine, ENC_BUCKET_BYTES, MAX_BRIDGES_PER_BUCKET}, proto::{ blockage_migration, check_blockage, issue_invite, level_up, migration, open_invite, redeem_invite, trust_promotion, }, - IssuerPubKey, + BridgeAuth, BridgeDb, IssuerPubKey, OPENINV_LENGTH, }; use rand::RngCore; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use std::{ - sync::{Arc, Mutex}, -}; - +use std::sync::{Arc, Mutex}; #[serde_as] #[derive(Serialize, Deserialize)] @@ -84,8 +75,7 @@ pub struct LoxServerContext { } impl LoxServerContext { - - pub fn append_extra_bridges(&self, bridge: BridgeLine){ + pub fn append_extra_bridges(&self, bridge: BridgeLine) { let mut extra_bridges = self.extra_bridges.lock().unwrap(); extra_bridges.push(bridge); } @@ -93,12 +83,11 @@ impl LoxServerContext { pub fn remove_extra_bridges(&self) -> [BridgeLine; MAX_BRIDGES_PER_BUCKET] { let mut extra_bridges = self.extra_bridges.lock().unwrap(); let mut return_bridges = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; - for i in 0..MAX_BRIDGES_PER_BUCKET{ + for i in 0..MAX_BRIDGES_PER_BUCKET { return_bridges[i] = extra_bridges.remove(i); } return_bridges - } pub fn new_unreplaced_bridge(&self, bridge: BridgeLine) { @@ -111,8 +100,6 @@ impl LoxServerContext { let mut db_obj = self.db.lock().unwrap(); let mut extra_bridges = self.extra_bridges.lock().unwrap(); ba_obj.allocate_bridges(&mut extra_bridges, &mut db_obj); - - } pub fn add_openinv_bucket(&self, bucket: [BridgeLine; 3]) { @@ -133,8 +120,8 @@ impl LoxServerContext { let mut available_bridge = eb_obj.last(); ba_obj.bridge_replace(&bridgeline, available_bridge, &mut db_obj) - } + pub fn add_unreachable(&self, bridgeline: BridgeLine) -> bool { let mut ba_obj = self.ba.lock().unwrap(); let mut db_obj = self.db.lock().unwrap(); @@ -273,7 +260,10 @@ pub fn verify_and_send_trust_promo(request: Bytes, context: LoxServerContext) -> prepare_header(trust_promo_resp_str) } -pub fn verify_and_send_trust_migration(request: Bytes, context: LoxServerContext) -> Response { +pub fn verify_and_send_trust_migration( + request: Bytes, + context: LoxServerContext, +) -> Response { let req: migration::Request = serde_json::from_slice(&request).unwrap(); let response = context.trust_migration(req); let resp_str = serde_json::to_string(&response).unwrap(); @@ -309,7 +299,10 @@ pub fn verify_and_send_check_blockage(request: Bytes, context: LoxServerContext) prepare_header(check_blockage_resp_str) } -pub fn verify_and_send_blockage_migration(request: Bytes, context: LoxServerContext) -> Response { +pub fn verify_and_send_blockage_migration( + request: Bytes, + context: LoxServerContext, +) -> Response { let req: blockage_migration::Request = serde_json::from_slice(&request).unwrap(); let response = context.blockage_migration(req); let resp_str = serde_json::to_string(&response).unwrap(); @@ -321,4 +314,4 @@ fn prepare_header(response: String) -> Response { resp.headers_mut() .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp -} \ No newline at end of file +} diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 1dbd0bb..e775fdb 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -1,19 +1,15 @@ use futures::future; use futures::StreamExt; use hyper::{ - body, - header::HeaderValue, server::conn::AddrStream, service::{make_service_fn, service_fn}, - Body, Method, Request, Response, Server, StatusCode, + Body, Request, Response, Server, }; -use lox::bridge_table::MAX_BRIDGES_PER_BUCKET; -use lox::bridge_table::{BridgeLine, BRIDGE_BYTES}; - +use lox::bridge_table::{BridgeLine, MAX_BRIDGES_PER_BUCKET}; use lox::{BridgeAuth, BridgeDb}; use rdsys_backend::{proto::ResourceDiff, start_stream}; -use serde::{Deserialize}; +use serde::Deserialize; use std::{ convert::Infallible, env, @@ -25,7 +21,10 @@ use std::{ }; mod lox_context; -use lox_context::LoxServerContext; +mod request_handler; +use request_handler::handle; +mod resource_parser; +use resource_parser::parse_resource; use tokio::{ signal, spawn, @@ -33,70 +32,6 @@ use tokio::{ time::sleep, }; -// Lox Request handling logic for each Lox request/protocol -async fn handle( - cloned_context: LoxServerContext, - req: Request, -) -> Result, Infallible> { - println!("Request: {:?}", req); - match req.method() { - &Method::OPTIONS => Ok(Response::builder() - .header("Access-Control-Allow-Origin", HeaderValue::from_static("*")) - .header("Access-Control-Allow-Headers", "accept, content-type") - .header("Access-Control-Allow-Methods", "POST") - .status(200) - .body(Body::from("Allow POST")) - .unwrap()), - _ => match (req.method(), req.uri().path()) { - (&Method::POST, "/invite") => Ok::<_, Infallible>(lox_context::generate_invite(cloned_context)), - (&Method::POST, "/reachability") => { - Ok::<_, Infallible>(lox_context::send_reachability_cred(cloned_context)) - } - (&Method::POST, "/pubkeys") => Ok::<_, Infallible>(lox_context::send_keys(cloned_context)), - (&Method::POST, "/openreq") => Ok::<_, Infallible>({ - let bytes = body::to_bytes(req.into_body()).await.unwrap(); - lox_context::verify_and_send_open_cred(bytes, cloned_context) - }), - (&Method::POST, "/trustpromo") => Ok::<_, Infallible>({ - let bytes = body::to_bytes(req.into_body()).await.unwrap(); - lox_context::verify_and_send_trust_promo(bytes, cloned_context) - }), - (&Method::POST, "/trustmig") => Ok::<_, Infallible>({ - let bytes = body::to_bytes(req.into_body()).await.unwrap(); - lox_context::verify_and_send_trust_migration(bytes, cloned_context) - }), - (&Method::POST, "/levelup") => Ok::<_, Infallible>({ - let bytes = body::to_bytes(req.into_body()).await.unwrap(); - lox_context::verify_and_send_level_up(bytes, cloned_context) - }), - (&Method::POST, "/issueinvite") => Ok::<_, Infallible>({ - let bytes = body::to_bytes(req.into_body()).await.unwrap(); - lox_context::verify_and_send_issue_invite(bytes, cloned_context) - }), - (&Method::POST, "/redeem") => Ok::<_, Infallible>({ - let bytes = body::to_bytes(req.into_body()).await.unwrap(); - lox_context::verify_and_send_redeem_invite(bytes, cloned_context) - }), - (&Method::POST, "/checkblockage") => Ok::<_, Infallible>({ - let bytes = body::to_bytes(req.into_body()).await.unwrap(); - // TEST ONLY: Block all existing bridges and add new ones for migration - lox_context::verify_and_send_check_blockage(bytes, cloned_context) - }), - (&Method::POST, "/blockagemigration") => Ok::<_, Infallible>({ - let bytes = body::to_bytes(req.into_body()).await.unwrap(); - lox_context::verify_and_send_blockage_migration(bytes, cloned_context) - }), - _ => { - // Return 404 not found response. - Ok(Response::builder() - .status(StatusCode::NOT_FOUND) - .body(Body::from("Not found")) - .unwrap()) - } - }, - } -} - async fn shutdown_signal() { tokio::signal::ctrl_c() .await @@ -104,7 +39,6 @@ async fn shutdown_signal() { println!("Shut down Lox Server"); } - #[derive(Debug, Deserialize)] struct ResourceInfo { endpoint: String, @@ -155,9 +89,7 @@ async fn rdsys_bridge_parser( async fn parse_bridges(rdsys_tx: mpsc::Sender, mut rx: mpsc::Receiver) { loop { let resourcediff = rx.recv().await.unwrap(); - let cmd = Command::Rdsys { - resourcediff, - }; + let cmd = Command::Rdsys { resourcediff }; rdsys_tx.send(cmd).await.unwrap(); sleep(Duration::from_secs(1)).await; } @@ -189,48 +121,21 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { while let Some(cmd) = context_rx.recv().await { use Command::*; - match cmd { Rdsys { resourcediff } => { if let Some(new_resources) = resourcediff.new { let mut count = 0; - let mut bucket= [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; + let mut bucket = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; for pt in new_resources { println!("A NEW RESOURCE: {:?}", pt); for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()] - .copy_from_slice(resource.address.as_bytes()); - let resource_uid = resource.get_uid().expect("Unable to get Fingerprint UID of resource"); - let infostr: String = format!( - "type={} blocked_in={:?} protocol={} fingerprint={:?} or_addresses={:?} distribution={} flags={:?} params={:?}", - resource.r#type, - resource.blocked_in, - resource.protocol, - resource.fingerprint, - resource.or_addresses, - resource.distribution, - resource.flags, - resource.params, - ); - let mut info_bytes: [u8; BRIDGE_BYTES - 26] = [0; BRIDGE_BYTES - 26]; - - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - uid_fingerprint: resource_uid, - info: info_bytes, - }; + let bridgeline = parse_resource(resource); println!("Now it's a bridgeline: {:?}", bridgeline); if context.unreplaced_bridges.lock().unwrap().len() > 0 { println!("BridgeLine to be replaced: {:?}", bridgeline); let res = context.replace_with_new(bridgeline); if res { - println!( - "BridgeLine successfully replaced: {:?}", - bridgeline - ); + println!("BridgeLine successfully replaced: {:?}", bridgeline); } else { // Add the bridge to the list of unreplaced bridges in the Lox context and try // again to replace at the next update (nothing changes in the Lox Authority) @@ -238,23 +143,25 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { context.new_unreplaced_bridge(bridgeline); } } else { - if count < MAX_BRIDGES_PER_BUCKET-1 { - bucket[count] = bridgeline; - count += 1; - } else { - // TODO: Decide the circumstances under which a bridge is allocated to an open_inv or spare bucket, - // eventually also do some more fancy grouping of new resources, i.e., by type or region - context.add_openinv_bucket(bucket); - count = 0; - bucket = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; + if count < MAX_BRIDGES_PER_BUCKET { + bucket[count] = bridgeline; + count += 1; + } else { + // TODO: Decide the circumstances under which a bridge is allocated to an open_inv or spare bucket, + // eventually also do some more fancy grouping of new resources, i.e., by type or region + context.add_openinv_bucket(bucket); + count = 0; + bucket = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; + } } } - } } // Handle the extra buckets that were not allocated already if count != 0 { for val in 0..count { - if context.extra_bridges.lock().unwrap().len() < (MAX_BRIDGES_PER_BUCKET-1) { + if context.extra_bridges.lock().unwrap().len() + < (MAX_BRIDGES_PER_BUCKET) + { context.append_extra_bridges(bucket[val]); } else { bucket = context.remove_extra_bridges(); @@ -267,31 +174,7 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { for pt in changed_resources { println!("A NEW CHANGED RESOURCE: {:?}", pt); for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()] - .copy_from_slice(resource.address.as_bytes()); - let resource_uid = resource.get_uid().expect("Unable to get Fingerprint UID of resource"); - let infostr: String = format!( - "type={} blocked_in={:?} protocol={} fingerprint= {:?} or_addresses={:?} distribution={} flags={:?} params={:?}", - resource.r#type, - resource.blocked_in, - resource.protocol, - resource.fingerprint, - resource.or_addresses, - resource.distribution, - resource.flags, - resource.params, - ); - let mut info_bytes: [u8; BRIDGE_BYTES - 26] = [0; BRIDGE_BYTES - 26]; - - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - uid_fingerprint: resource_uid, - info: info_bytes, - }; - + let bridgeline = parse_resource(resource); println!("BridgeLine to be changed: {:?}", bridgeline); let res = context.update_bridge(bridgeline); if res { @@ -304,7 +187,6 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { let bucket = context.remove_extra_bridges(); context.add_spare_bucket(bucket); } - } } } @@ -319,44 +201,20 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { for pt in gone_resources { println!("A NEW GONE RESOURCE: {:?}", pt); for resource in pt.1 { - let mut ip_bytes: [u8; 16] = [0; 16]; - ip_bytes[..resource.address.len()] - .copy_from_slice(resource.address.as_bytes()); - let resource_uid = resource.get_uid().expect("Unable to get Fingerprint UID of resource"); - let infostr: String = format!( - "type={} blocked_in={:?} protocol={} fingerprint={:?} or_addresses={:?} distribution={} flags={:?} params={:?}", - resource.r#type, - resource.blocked_in, - resource.protocol, - resource.fingerprint, - resource.or_addresses, - resource.distribution, - resource.flags, - resource.params, - ); - let mut info_bytes: [u8; BRIDGE_BYTES - 26] = [0; BRIDGE_BYTES - 26]; - - info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); - let bridgeline = BridgeLine { - addr: ip_bytes, - port: resource.port, - uid_fingerprint: resource_uid, - info: info_bytes, - }; + let bridgeline = parse_resource(resource); println!("BridgeLine to be replaced: {:?}", bridgeline); let res = context.replace_with_new(bridgeline); if res { - println!( - "BridgeLine successfully replaced: {:?}", - bridgeline - ); + println!("BridgeLine successfully replaced: {:?}", bridgeline); } else { // Add the bridge to the list of unreplaced bridges in the Lox context and try // again to replace at the next update (nothing changes in the Lox Authority) - println!("'Gone' BridgeLine NOT replaced, saved for next update! : {:?}", bridgeline); + println!( + "'Gone' BridgeLine NOT replaced, saved for next update! : {:?}", + bridgeline + ); context.new_unreplaced_bridge(bridgeline); } - } } } @@ -375,12 +233,11 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { println!("'Gone' BridgeLine NOT REMOVED!! : {:?}", bridgeline); //TODO probably do something else here } - */ + */ context.allocate_leftover_bridges(); context.encrypt_table(); sleep(Duration::from_millis(1)).await; } - Request { req, sender } => { let response = handle(context.clone(), req).await; if let Err(e) = sender.send(response) { diff --git a/crates/lox-distributor/src/request_handler.rs b/crates/lox-distributor/src/request_handler.rs new file mode 100644 index 0000000..98682a4 --- /dev/null +++ b/crates/lox-distributor/src/request_handler.rs @@ -0,0 +1,74 @@ +use hyper::{body, header::HeaderValue, Body, Method, Request, Response, StatusCode}; + +use std::convert::Infallible; + +use crate::lox_context; +use crate::lox_context::LoxServerContext; + +// Lox Request handling logic for each Lox request/protocol +pub async fn handle( + cloned_context: LoxServerContext, + req: Request, +) -> Result, Infallible> { + println!("Request: {:?}", req); + match req.method() { + &Method::OPTIONS => Ok(Response::builder() + .header("Access-Control-Allow-Origin", HeaderValue::from_static("*")) + .header("Access-Control-Allow-Headers", "accept, content-type") + .header("Access-Control-Allow-Methods", "POST") + .status(200) + .body(Body::from("Allow POST")) + .unwrap()), + _ => match (req.method(), req.uri().path()) { + (&Method::POST, "/invite") => { + Ok::<_, Infallible>(lox_context::generate_invite(cloned_context)) + } + (&Method::POST, "/reachability") => { + Ok::<_, Infallible>(lox_context::send_reachability_cred(cloned_context)) + } + (&Method::POST, "/pubkeys") => { + Ok::<_, Infallible>(lox_context::send_keys(cloned_context)) + } + (&Method::POST, "/openreq") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + lox_context::verify_and_send_open_cred(bytes, cloned_context) + }), + (&Method::POST, "/trustpromo") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + lox_context::verify_and_send_trust_promo(bytes, cloned_context) + }), + (&Method::POST, "/trustmig") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + lox_context::verify_and_send_trust_migration(bytes, cloned_context) + }), + (&Method::POST, "/levelup") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + lox_context::verify_and_send_level_up(bytes, cloned_context) + }), + (&Method::POST, "/issueinvite") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + lox_context::verify_and_send_issue_invite(bytes, cloned_context) + }), + (&Method::POST, "/redeem") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + lox_context::verify_and_send_redeem_invite(bytes, cloned_context) + }), + (&Method::POST, "/checkblockage") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + // TEST ONLY: Block all existing bridges and add new ones for migration + lox_context::verify_and_send_check_blockage(bytes, cloned_context) + }), + (&Method::POST, "/blockagemigration") => Ok::<_, Infallible>({ + let bytes = body::to_bytes(req.into_body()).await.unwrap(); + lox_context::verify_and_send_blockage_migration(bytes, cloned_context) + }), + _ => { + // Return 404 not found response. + Ok(Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::from("Not found")) + .unwrap()) + } + }, + } +} diff --git a/crates/lox-distributor/src/resource_parser.rs b/crates/lox-distributor/src/resource_parser.rs new file mode 100644 index 0000000..6790fa5 --- /dev/null +++ b/crates/lox-distributor/src/resource_parser.rs @@ -0,0 +1,30 @@ +use lox::bridge_table::{BridgeLine, BRIDGE_BYTES}; +use rdsys_backend::proto::Resource; + +pub fn parse_resource(resource: Resource) -> BridgeLine { + let mut ip_bytes: [u8; 16] = [0; 16]; + ip_bytes[..resource.address.len()].copy_from_slice(resource.address.as_bytes()); + let resource_uid = resource + .get_uid() + .expect("Unable to get Fingerprint UID of resource"); + let infostr: String = format!( + "type={} blocked_in={:?} protocol={} fingerprint={:?} or_addresses={:?} distribution={} flags={:?} params={:?}", + resource.r#type, + resource.blocked_in, + resource.protocol, + resource.fingerprint, + resource.or_addresses, + resource.distribution, + resource.flags, + resource.params, +); + let mut info_bytes: [u8; BRIDGE_BYTES - 26] = [0; BRIDGE_BYTES - 26]; + + info_bytes[..infostr.len()].copy_from_slice(infostr.as_bytes()); + BridgeLine { + addr: ip_bytes, + port: resource.port, + uid_fingerprint: resource_uid, + info: info_bytes, + } +} From 6372e894aef6fcc34bb2f3bc42f1bc084346b7cc Mon Sep 17 00:00:00 2001 From: onyinyang Date: Wed, 17 May 2023 12:46:09 -0400 Subject: [PATCH 39/39] Adjust replace_with_new to fit with updates to Lox library --- crates/lox-distributor/src/lox_context.rs | 18 +++++++++++++----- crates/lox-distributor/src/main.rs | 18 ++++++++---------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/crates/lox-distributor/src/lox_context.rs b/crates/lox-distributor/src/lox_context.rs index c9993a0..6c476e2 100644 --- a/crates/lox-distributor/src/lox_context.rs +++ b/crates/lox-distributor/src/lox_context.rs @@ -90,6 +90,12 @@ impl LoxServerContext { return_bridges } + pub fn remove_single_bridge(&self) { + let mut extra_bridges = self.extra_bridges.lock().unwrap(); + let length = extra_bridges.len(); + _ = extra_bridges.remove(length - 1) + } + pub fn new_unreplaced_bridge(&self, bridge: BridgeLine) { let mut unreplaced_bridges = self.unreplaced_bridges.lock().unwrap(); unreplaced_bridges.push(bridge); @@ -115,11 +121,13 @@ impl LoxServerContext { pub fn replace_with_new(&self, bridgeline: BridgeLine) -> bool { let mut ba_obj = self.ba.lock().unwrap(); - let mut db_obj = self.db.lock().unwrap(); - let mut eb_obj = self.extra_bridges.lock().unwrap(); - let mut available_bridge = eb_obj.last(); - - ba_obj.bridge_replace(&bridgeline, available_bridge, &mut db_obj) + let eb_obj = self.extra_bridges.lock().unwrap(); + let available_bridge = eb_obj.last(); + // .last() doesn't actually remove the object so we still have to do that + if eb_obj.len() > 0 { + self.remove_single_bridge(); + } + ba_obj.bridge_replace(&bridgeline, available_bridge) } pub fn add_unreachable(&self, bridgeline: BridgeLine) -> bool { diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index e775fdb..7c62334 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -142,17 +142,15 @@ async fn context_manager(mut context_rx: mpsc::Receiver) { println!("'Gone' BridgeLine NOT replaced, saved for next update! : {:?}", bridgeline); context.new_unreplaced_bridge(bridgeline); } + } else if count < MAX_BRIDGES_PER_BUCKET { + bucket[count] = bridgeline; + count += 1; } else { - if count < MAX_BRIDGES_PER_BUCKET { - bucket[count] = bridgeline; - count += 1; - } else { - // TODO: Decide the circumstances under which a bridge is allocated to an open_inv or spare bucket, - // eventually also do some more fancy grouping of new resources, i.e., by type or region - context.add_openinv_bucket(bucket); - count = 0; - bucket = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; - } + // TODO: Decide the circumstances under which a bridge is allocated to an open_inv or spare bucket, + // eventually also do some more fancy grouping of new resources, i.e., by type or region + context.add_openinv_bucket(bucket); + count = 0; + bucket = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; } } }