diff --git a/src/ping.rs b/src/ping.rs index 4c15700..0ce3465 100644 --- a/src/ping.rs +++ b/src/ping.rs @@ -7,6 +7,7 @@ extern crate rand; use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; use rand::Rng; use rand::distributions::Alphanumeric; @@ -17,32 +18,49 @@ use sha2::{Sha256, Digest}; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Ping { + time : u128, salt : String, hash : String } +const MAX_PING_AGE: i64 = 30000; +const MIN_PING_AGE: i64 = -5000; + impl Ping { pub fn new (auth_token : Arc) -> Ping { let salt = rand::thread_rng() .sample_iter(&Alphanumeric) - .take(30) + .take(50) .collect::(); - let hash = hash_token_with_salt(auth_token, &salt); - Ping { salt, hash } + let time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(); + let hash = hash_token_with_salt(auth_token, time, &salt); + Ping { time, salt, hash } } pub fn verify(&self, auth_token : Arc) -> bool { - let hash = hash_token_with_salt(auth_token, &self.salt); - eprintln!("Ping.verify: INFO: comparing provided hash={} with calculated hash={}", self.hash, hash); - self.hash.eq(&hash) + let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(); + let age : i64 = (now - self.time) as i64; + return if age > MAX_PING_AGE { + eprintln!("Ping.verify: ERROR: ping was too old"); + false + } else if age < MIN_PING_AGE { + eprintln!("Ping.verify: ERROR: ping was too young"); + false + } else { + let hash = hash_token_with_salt(auth_token, self.time, &self.salt); + eprintln!("Ping.verify: INFO: comparing provided hash={} with calculated hash={}", self.hash, hash); + self.hash.eq(&hash) + } } } -fn hash_token_with_salt(auth_token: Arc, salt: &String) -> String { +fn hash_token_with_salt(auth_token: Arc, time : u128, salt: &String) -> String { let mut hasher = Sha256::new(); hasher.update(salt.as_bytes()); hasher.update(b":"); + hasher.update(time.to_string()); + hasher.update(b":"); hasher.update(auth_token.to_string()); let digest = hasher.finalize(); let hash = hex::encode(digest); diff --git a/src/proxy.rs b/src/proxy.rs index 50209e3..922d4c3 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -82,6 +82,8 @@ pub async fn start_proxy (dns1_ip : &str, eprintln!("start_proxy: INFO Proxy await result: {:?}", result); } +const HEADER_FLEX_AUTH: &'static str = "X-Bubble-Flex-Auth"; + async fn proxy(client: Client>>, gateway: Arc, resolver: Arc, @@ -97,8 +99,8 @@ async fn proxy(client: Client>>, let ping : Ping = serde_json::from_str(body.as_str()).unwrap(); eprintln!("proxy: INFO: received body: {:?}", ping); if !ping.verify(auth_token.clone()) { - eprintln!("proxy: INFO: ping hash not valid"); - bad_request("ping hash not valid") + eprintln!("proxy: ERROR: invalid ping hash"); + bad_request("invalid ping hash") } else { let pong = Ping::new(auth_token.clone()); let pong_json = serde_json::to_string(&pong).unwrap(); @@ -106,9 +108,28 @@ async fn proxy(client: Client>>, } } else { eprintln!("proxy: ERROR: no host"); - bad_request("No host!") + bad_request("No host") } } + + let headers = req.headers(); + let flex_auth_header = headers.get(HEADER_FLEX_AUTH); + if flex_auth_header.is_none() { + eprintln!("proxy: ERROR: no auth"); + return bad_request("No auth"); + } + let flex_auth = flex_auth_header.unwrap().to_str(); + if flex_auth.is_err() { + eprintln!("proxy: ERROR: auth not found"); + return bad_request("auth not found"); + } + + let auth : Ping = serde_json::from_str(flex_auth.unwrap().to_string().as_str()).unwrap(); + if !auth.verify(auth_token.clone()) { + eprintln!("proxy: ERROR: invalid auth"); + return bad_request("invalid auth"); + } + let host = host.unwrap(); let ip_string = resolve_with_cache(host, &resolver, resolver_cache).await; eprintln!("proxy: INFO req(host {} resolved to: {}): {:?}", host, ip_string, req);