Browse Source

WIP. move proxy server into proxy module, implement read/write bcrypt password

master
Jonathan Cobb 4 years ago
parent
commit
98078bee81
5 changed files with 168 additions and 77 deletions
  1. +68
    -0
      Cargo.lock
  2. +2
    -0
      Cargo.toml
  3. +3
    -56
      src/main.rs
  4. +40
    -12
      src/pass.rs
  5. +55
    -9
      src/proxy.rs

+ 68
- 0
Cargo.lock View File

@@ -87,6 +87,25 @@ dependencies = [
"rustc-demangle", "rustc-demangle",
] ]


[[package]]
name = "base64"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"

[[package]]
name = "bcrypt"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f055c8591efe08e03f534ee632672ea3643c3932e485f422107ec6cc1157b0ea"
dependencies = [
"base64",
"blowfish",
"byteorder",
"lazy_static",
"rand",
]

[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "0.5.0" version = "0.5.0"
@@ -99,10 +118,31 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"


[[package]]
name = "block-cipher-trait"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
dependencies = [
"generic-array",
]

[[package]]
name = "blowfish"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
dependencies = [
"block-cipher-trait",
"byteorder",
"opaque-debug",
]

[[package]] [[package]]
name = "bubble-flexrouter" name = "bubble-flexrouter"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bcrypt",
"clap", "clap",
"futures", "futures",
"futures-channel", "futures-channel",
@@ -113,12 +153,19 @@ dependencies = [
"hyper-tls", "hyper-tls",
"lru", "lru",
"pnet", "pnet",
"rand",
"tokio", "tokio",
"tower", "tower",
"trust-dns-resolver", "trust-dns-resolver",
"whoami", "whoami",
] ]


[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"

[[package]] [[package]]
name = "bytes" name = "bytes"
version = "0.5.6" version = "0.5.6"
@@ -312,6 +359,15 @@ dependencies = [
"slab", "slab",
] ]


[[package]]
name = "generic-array"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
dependencies = [
"typenum",
]

[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.1.14" version = "0.1.14"
@@ -720,6 +776,12 @@ version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad"


[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"

[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.30" version = "0.10.30"
@@ -1511,6 +1573,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"


[[package]]
name = "typenum"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"

[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.4" version = "0.3.4"


+ 2
- 0
Cargo.toml View File

@@ -6,6 +6,7 @@ authors = ["Jonathan Cobb <jonathan@getbubblenow.com>"]
edition = "2018" edition = "2018"


[dependencies] [dependencies]
bcrypt = "0.6.3"
clap = "2.33.0" clap = "2.33.0"
futures = "0.3.5" futures = "0.3.5"
futures-core = { version = "0.3", default-features = false } futures-core = { version = "0.3", default-features = false }
@@ -16,6 +17,7 @@ hyper = { version = "0.13.7", features = ["stream"] }
hyper-tls = "0.4.3" hyper-tls = "0.4.3"
lru = "0.6.0" lru = "0.6.0"
pnet = "0.26.0" pnet = "0.26.0"
rand = "0.7.3"
tokio = { version = "0.2.22", features = ["full"] } tokio = { version = "0.2.22", features = ["full"] }
tower = "0.3.1" tower = "0.3.1"
trust-dns-resolver = "0.19.5" trust-dns-resolver = "0.19.5"


+ 3
- 56
src/main.rs View File

@@ -6,32 +6,16 @@


extern crate lru; extern crate lru;


use std::convert::Infallible;
use std::net::SocketAddr;
use std::process::exit; use std::process::exit;
use std::sync::Arc;


use clap::{Arg, ArgMatches, App}; use clap::{Arg, ArgMatches, App};


use hyper::service::{make_service_fn, service_fn};
use hyper::{Client, Server};
use hyper::client::HttpConnector;
use hyper_tls::HttpsConnector;

use lru::LruCache;

use pnet::datalink; use pnet::datalink;


use tokio::sync::Mutex;

use whoami; use whoami;


use bubble_flexrouter::pass::init_password; use bubble_flexrouter::pass::init_password;
use bubble_flexrouter::dns_cache::*;
use bubble_flexrouter::net::*;
use bubble_flexrouter::proxy::*;

type HttpClient = Client<hyper_tls::HttpsConnector<HttpConnector<CacheResolver>>, hyper::Body>;
use bubble_flexrouter::proxy::start_proxy;


// To try this example: // To try this example:
// 1. cargo run --example http_proxy // 1. cargo run --example http_proxy
@@ -134,7 +118,7 @@ async fn main() {
let password_file = password_file_opt.unwrap(); let password_file = password_file_opt.unwrap();


let password_opt = args.value_of("password_env_var"); let password_opt = args.value_of("password_env_var");
//let password = init_password(password_file, password_opt);
let password = init_password(password_file, password_opt);


let proxy_ip_opt = args.value_of("proxy_ip"); let proxy_ip_opt = args.value_of("proxy_ip");
if proxy_ip_opt.is_none() { if proxy_ip_opt.is_none() {
@@ -160,44 +144,7 @@ async fn main() {
} }


let dns1_ip = args.value_of("dns1").unwrap(); let dns1_ip = args.value_of("dns1").unwrap();
let dns1_sock : SocketAddr = format!("{}:53", dns1_ip).parse().unwrap();
let dns2_ip = args.value_of("dns2").unwrap(); let dns2_ip = args.value_of("dns2").unwrap();
let dns2_sock : SocketAddr = format!("{}:53", dns2_ip).parse().unwrap();

let resolver = Arc::new(create_resolver(dns1_sock, dns2_sock).await);
let resolver_cache = Arc::new(Mutex::new(LruCache::new(1000)));

let http_resolver = CacheResolver::new(resolver.clone(), resolver_cache.clone());
let connector = HttpConnector::new_with_resolver(http_resolver);
let https = HttpsConnector::new_with_connector(connector);
let client: HttpClient = Client::builder().build(https);
let gateway = Arc::new(ip_gateway());

let proxy_port = args.value_of("proxy_port").unwrap().parse::<u16>().unwrap(); let proxy_port = args.value_of("proxy_port").unwrap().parse::<u16>().unwrap();
let addr = SocketAddr::from((bind_addr.unwrap().ip(), proxy_port));

let make_service = make_service_fn(move |_| {
let client = client.clone();
let gateway = gateway.clone();
let resolver = resolver.clone();
let resolver_cache = resolver_cache.clone();
async move {
Ok::<_, Infallible>(service_fn(
move |req| proxy(
client.clone(),
gateway.clone(),
resolver.clone(),
resolver_cache.clone(),
req)
))
}
});

let server = Server::bind(&addr).serve(make_service);

println!("Listening on http://{}", addr);

if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
start_proxy(dns1_ip, dns2_ip, bind_addr.unwrap().ip(), proxy_port);
} }

+ 40
- 12
src/pass.rs View File

@@ -4,47 +4,75 @@
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ * For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/
*/ */


extern crate bcrypt;
extern crate rand;

use std::env; use std::env;
use std::fs; use std::fs;
use std::fs::File; use std::fs::File;
use std::path::Path; use std::path::Path;
use std::process::exit; use std::process::exit;


pub fn init_password (password_file : &str, password_opt : Option<&str>) -> String {
use rand::distributions::Alphanumeric;
use self::rand::Rng;
use std::io::Write;

pub fn init_password (password_file_name : &str, password_opt : Option<&str>) -> String {
if password_opt.is_some() { if password_opt.is_some() {
let password_env_var = password_opt.unwrap(); let password_env_var = password_opt.unwrap();
let password_env_var_result = env::var(password_env_var); let password_env_var_result = env::var(password_env_var);
if password_env_var_result.is_err() { if password_env_var_result.is_err() {
eprintln!("\nERROR: password-env-var argument was {} but that environment variable was not defined\n", password_env_var); eprintln!("\nERROR: password-env-var argument was {} but that environment variable was not defined\n", password_env_var);
exit(2);
exit(3);
} }
let password_val = password_env_var_result.unwrap(); let password_val = password_env_var_result.unwrap();
if password_val.trim().len() == 0 { if password_val.trim().len() == 0 {
eprintln!("\nERROR: password-env-var argument was {} but the value of that environment variable was empty\n", password_env_var); eprintln!("\nERROR: password-env-var argument was {} but the value of that environment variable was empty\n", password_env_var);
exit(2);
exit(3);
} }
let password_path = Path::new(password_file);
let password_path = Path::new(password_file_name);

let password_file_result = File::create(password_path); let password_file_result = File::create(password_path);
if password_file_result.is_err() { if password_file_result.is_err() {
let err = password_file_result.err(); let err = password_file_result.err();
if err.is_none() { if err.is_none() {
eprintln!("\nERROR: unknown error writing to password file {}\n", password_file);
eprintln!("\nERROR: unknown error writing to password file {}\n", password_file_name);
} else {
eprintln!("\nERROR: error writing to password file {}: {:?}\n", password_file_name, err);
}
exit(3);
}
let mut password_file = password_file_result.unwrap();

let salt = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(10)
.collect::<String>();
let mut bcrypted_pass : [u8; 24] = [0; 24];
bcrypt::bcrypt(14, &salt.as_bytes(), password_val.as_bytes(), &mut bcrypted_pass);

let write_result = password_file.write_all(&bcrypted_pass);
if write_result.is_err() {
let err = write_result.err();
if err.is_none() {
eprintln!("\nERROR: unknown error writing password file {}\n", password_file_name);
} else { } else {
eprintln!("\nERROR: error writing to password file {}: {:?}\n", password_file, err);
eprintln!("\nERROR: error writing password file {}: {:?}\n", password_file_name, err.unwrap());
} }
exit(2);
exit(3);
} }
} }


let result = fs::read_to_string(&password_file);
let result = fs::read_to_string(&password_file_name);
if result.is_err() { if result.is_err() {
let err = result.err(); let err = result.err();
if err.is_none() { if err.is_none() {
eprintln!("\nERROR: unknown error reading password file {}\n", password_file);
eprintln!("\nERROR: unknown error reading password file {}\n", password_file_name);
} else { } else {
eprintln!("\nERROR: error reading password file {}: {:?}\n", password_file, err.unwrap());
eprintln!("\nERROR: error reading password file {}: {:?}\n", password_file_name, err.unwrap());
} }
exit(2);
exit(3);
} }

return result.unwrap(); return result.unwrap();
}
}

+ 55
- 9
src/proxy.rs View File

@@ -6,14 +6,16 @@


extern crate lru; extern crate lru;


use std::net::SocketAddr;
use std::convert::Infallible;
use std::net::{IpAddr, SocketAddr};
use std::sync::Arc; use std::sync::Arc;


use futures_util::future::try_join; use futures_util::future::try_join;


use hyper::upgrade::Upgraded;
use hyper::{Body, Client, Method, Request, Response};
use hyper::{Body, Client, Method, Request, Response, Server};
use hyper::client::HttpConnector; use hyper::client::HttpConnector;
use hyper::service::{make_service_fn, service_fn};
use hyper::upgrade::Upgraded;
use hyper_tls::HttpsConnector; use hyper_tls::HttpsConnector;


use lru::LruCache; use lru::LruCache;
@@ -27,13 +29,57 @@ use crate::dns_cache::*;
use crate::net::*; use crate::net::*;
use crate::hyper_util::bad_request; use crate::hyper_util::bad_request;


//type HttpClient = Client<hyper_tls::HttpsConnector<HttpConnector<CacheResolver>>, hyper::Body>;
type HttpClient = Client<hyper_tls::HttpsConnector<HttpConnector<CacheResolver>>, hyper::Body>;

pub async fn start_proxy (dns1_ip : &str,
dns2_ip: &str,
proxy_ip: IpAddr,
proxy_port: u16) {
let dns1_sock : SocketAddr = format!("{}:53", dns1_ip).parse().unwrap();
let dns2_sock : SocketAddr = format!("{}:53", dns2_ip).parse().unwrap();

let resolver = Arc::new(create_resolver(dns1_sock, dns2_sock).await);
let resolver_cache = Arc::new(Mutex::new(LruCache::new(1000)));

let http_resolver = CacheResolver::new(resolver.clone(), resolver_cache.clone());
let connector = HttpConnector::new_with_resolver(http_resolver);
let https = HttpsConnector::new_with_connector(connector);
let client: HttpClient = Client::builder().build(https);
let gateway = Arc::new(ip_gateway());

let addr = SocketAddr::from((proxy_ip, proxy_port));

let make_service = make_service_fn(move |_| {
let client = client.clone();
let gateway = gateway.clone();
let resolver = resolver.clone();
let resolver_cache = resolver_cache.clone();
async move {
Ok::<_, Infallible>(service_fn(
move |req| proxy(
client.clone(),
gateway.clone(),
resolver.clone(),
resolver_cache.clone(),
req)
))
}
});

let server = Server::bind(&addr).serve(make_service);

println!("Listening on http://{}", addr);

if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
}


pub async fn proxy(client: Client<HttpsConnector<HttpConnector<CacheResolver>>>,
gateway: Arc<String>,
resolver: Arc<TokioAsyncResolver>,
resolver_cache: Arc<Mutex<LruCache<String, String>>>,
req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
async fn proxy(client: Client<HttpsConnector<HttpConnector<CacheResolver>>>,
gateway: Arc<String>,
resolver: Arc<TokioAsyncResolver>,
resolver_cache: Arc<Mutex<LruCache<String, String>>>,
req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
let host = req.uri().host(); let host = req.uri().host();
if host.is_none() { if host.is_none() {
return bad_request("No host!"); return bad_request("No host!");


Loading…
Cancel
Save