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