Просмотр исходного кода

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

master
Jonathan Cobb 4 лет назад
Родитель
Сommit
98078bee81
5 измененных файлов: 168 добавлений и 77 удалений
  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 Просмотреть файл

@@ -87,6 +87,25 @@ dependencies = [
"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]]
name = "bitflags"
version = "0.5.0"
@@ -99,10 +118,31 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "bubble-flexrouter"
version = "0.1.0"
dependencies = [
"bcrypt",
"clap",
"futures",
"futures-channel",
@@ -113,12 +153,19 @@ dependencies = [
"hyper-tls",
"lru",
"pnet",
"rand",
"tokio",
"tower",
"trust-dns-resolver",
"whoami",
]

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

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

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

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

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

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

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

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


+ 2
- 0
Cargo.toml Просмотреть файл

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

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


+ 3
- 56
src/main.rs Просмотреть файл

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

extern crate lru;

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

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 tokio::sync::Mutex;

use whoami;

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:
// 1. cargo run --example http_proxy
@@ -134,7 +118,7 @@ async fn main() {
let password_file = password_file_opt.unwrap();

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");
if proxy_ip_opt.is_none() {
@@ -160,44 +144,7 @@ async fn main() {
}

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_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 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 Просмотреть файл

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

extern crate bcrypt;
extern crate rand;

use std::env;
use std::fs;
use std::fs::File;
use std::path::Path;
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() {
let password_env_var = password_opt.unwrap();
let password_env_var_result = env::var(password_env_var);
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);
exit(2);
exit(3);
}
let password_val = password_env_var_result.unwrap();
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);
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);
if password_file_result.is_err() {
let err = password_file_result.err();
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 {
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() {
let err = result.err();
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 {
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();
}
}

+ 55
- 9
src/proxy.rs Просмотреть файл

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

extern crate lru;

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

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::service::{make_service_fn, service_fn};
use hyper::upgrade::Upgraded;
use hyper_tls::HttpsConnector;

use lru::LruCache;
@@ -27,13 +29,57 @@ use crate::dns_cache::*;
use crate::net::*;
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();
if host.is_none() {
return bad_request("No host!");


Загрузка…
Отмена
Сохранить