From 506d57e6f9eb1f98120ccf90f01bc5d6d87524e4 Mon Sep 17 00:00:00 2001 From: Kleo Dev Date: Fri, 15 Aug 2025 23:15:27 +0200 Subject: [PATCH] Working proxy with headers (not the best for privacy) --- Cargo.lock | 203 ++++++++++++++++++++++++++++++++++++++++++++------ Cargo.toml | 7 +- src/main.rs | 16 ++-- src/server.rs | 183 +++++++++++++++++++++------------------------ 4 files changed, 276 insertions(+), 133 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index efa396c..f92e7a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + [[package]] name = "aws-lc-rs" version = "1.13.3" @@ -356,10 +362,11 @@ dependencies = [ name = "ghostnet-rs" version = "0.0.1-alpha" dependencies = [ + "hyper 0.14.32", "reqwest", "rustls", "rustls-native-certs", - "rustls-pki-types", + "tokio", ] [[package]] @@ -374,6 +381,25 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.12" @@ -385,7 +411,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http", + "http 1.3.1", "indexmap", "slab", "tokio", @@ -408,6 +434,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.3.1" @@ -419,6 +456,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.1" @@ -426,7 +474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.3.1", ] [[package]] @@ -437,8 +485,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "pin-project-lite", ] @@ -448,6 +496,36 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.6.0" @@ -457,9 +535,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", @@ -474,8 +552,8 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http", - "hyper", + "http 1.3.1", + "hyper 1.6.0", "hyper-util", "rustls", "rustls-pki-types", @@ -492,7 +570,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-util", "native-tls", "tokio", @@ -511,14 +589,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", - "http-body", - "hyper", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.6.0", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.0", "system-configuration", "tokio", "tower-service", @@ -751,6 +829,16 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.27" @@ -881,6 +969,29 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -948,6 +1059,15 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.11.1" @@ -989,11 +1109,11 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-rustls", "hyper-tls", "hyper-util", @@ -1140,6 +1260,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "2.11.1" @@ -1226,6 +1352,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.11" @@ -1238,6 +1373,16 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket2" version = "0.6.0" @@ -1346,12 +1491,26 @@ dependencies = [ "io-uring", "libc", "mio", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "slab", - "socket2", + "socket2 0.6.0", + "tokio-macros", "windows-sys 0.59.0", ] +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -1409,8 +1568,8 @@ dependencies = [ "bitflags", "bytes", "futures-util", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "iri-string", "pin-project-lite", "tower", diff --git a/Cargo.toml b/Cargo.toml index a719fe2..4d07d47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,10 @@ edition = "2024" name = "ghostnet-rs" [dependencies] -reqwest = { version = "0.12.23", features = ["blocking"] } rustls = "0.23.31" rustls-native-certs = "0.8.1" -rustls-pki-types = "1.12.0" + +reqwest = { version = "0.12.23", features = ["blocking"] } + +hyper = { version = "0.14", features = ["full"] } +tokio = { version = "1", features = ["full"] } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 7ce3b77..193e36f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,8 @@ -fn main() { - ghostnet_rs::server::run(); +#[tokio::main] +async fn main() { + ghostnet_rs::server::run().await.unwrap(); // println!( - // "{}", - // ghostnet_rs::request("ghostnet-rs.onrender.com:443", "https://wikipedia.org") + // "{}", + // ghostnet_rs::request("ghostnet-rs.onrender.com:443", "https://wikipedia.org") // ); - // println!( - // "{}", - // reqwest::blocking::get("https://ghostnet-rs.onrender.com/") - // .unwrap() - // .text() - // .unwrap() - // ) } diff --git a/src/server.rs b/src/server.rs index 5344b2b..f06708e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,108 +1,95 @@ -use std::io::{Read, Write}; -use std::net::TcpListener; +use hyper::service::{make_service_fn, service_fn}; +use hyper::{Body, Request, Response, Server}; +use reqwest; +use reqwest::header::{HeaderName, HeaderValue}; +use std::convert::Infallible; +use std::net::SocketAddr; use std::str::FromStr; +use tokio; -use reqwest::Version; -use reqwest::blocking::Client; -use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; +const DEFAULT_TARGET: &str = "https://crackmes.one"; +const GHOST_ROUTE_HEADER: &str = "ghost-route"; -pub fn run() { - let listener = TcpListener::bind(format!( - "0.0.0.0:{}", - std::env::var("PORT").unwrap_or_else(|_| "3000".into()) - )) - .unwrap(); +async fn handle_request(req: Request) -> Result, Infallible> { + let target_url = req + .headers() + .get(GHOST_ROUTE_HEADER) + .and_then(|v| v.to_str().ok()) + .unwrap_or(DEFAULT_TARGET); - loop { - let (mut stream, _) = listener.accept().unwrap(); + let url_params = req + .uri() + .path_and_query() + .map(|pq| pq.as_str()) + .unwrap_or(""); - let mut buf = [0; 1024]; - if let Ok(len) = stream.read(&mut buf) { - let buf_str = String::from_utf8_lossy(&buf[..len]).to_string(); - if buf_str.starts_with("ROUTE") { - let addr = buf_str - .split_once("\n") - .unwrap() - .0 - .split_once(" ") - .unwrap() - .1; - let http = buf_str.split_once("\n").unwrap().1; - println!("Sending request to {addr:?} with http: {http:?}"); - stream - .write_all(send_request(addr, http).as_bytes()) - .unwrap(); - stream.flush().unwrap(); - } else { - println!("Sending default request"); - stream - .write_all(send_request("https://wikipedia.org", "GET / HTTP/1.1").as_bytes()) - .unwrap(); - stream.flush().unwrap(); - } - } - } + let client = reqwest::Client::new(); + + let builder = client + .request( + reqwest::Method::from_str(req.method().as_str()).unwrap(), + format!("{}/{}", target_url.trim_end_matches('/'), url_params), + ) + .headers(reqwest::header::HeaderMap::from_iter( + req.headers() + .into_iter() + .map(|h| { + if h.0.as_str() == "host" { + ( + HeaderName::from_str("host").unwrap(), + HeaderValue::from_bytes( + reqwest::Url::from_str(target_url) + .unwrap() + .host_str() + .unwrap() + .as_bytes(), + ) + .unwrap(), + ) + } else { + ( + HeaderName::from_str(h.0.as_str()).unwrap(), + HeaderValue::from_bytes(h.1.as_bytes()).unwrap(), + ) + } + }) + .collect::>(), + )); + + let response = builder.send().await.unwrap(); + + return Ok(Response::new(Body::from(response.text().await.unwrap()))); } -fn send_request(url: &str, request: &str) -> String { - let client = Client::new(); - let mut lines = request.lines(); - - let request_line = lines.next().unwrap(); - let mut parts = request_line.split_whitespace(); - let method = parts.next().unwrap_or("GET"); - // Ignore version for now - - let mut headers = Vec::new(); - for line in lines.clone() { - if line.is_empty() { - break; // end of headers - } - if let Some((key, value)) = line.split_once(':') { - headers.push(( - HeaderName::from_str(key.trim()).unwrap(), - HeaderValue::from_str(value.trim()).unwrap(), - )); - } - } - - let body: String = lines.collect::>().join("\n"); - - let builder = match method { - "GET" => client.get(url), - "POST" => client.post(url).body(body.clone()), - "PUT" => client.put(url).body(body.clone()), - "DELETE" => client.delete(url), - _ => client.get(url), - } - .headers(HeaderMap::from_iter(headers.into_iter())); - - let resp = builder.send().unwrap(); - - let mut http_string = String::new(); - - http_string.push_str(&format!( - "HTTP/{} {} {}\r\n", - match resp.version() { - Version::HTTP_09 => "0.9", - Version::HTTP_10 => "1.0", - Version::HTTP_11 => "1.1", - Version::HTTP_2 => "2.0", - Version::HTTP_3 => "3.0", - _ => "2.0", - }, - resp.status().as_u16(), - resp.status().canonical_reason().unwrap_or("") - )); - - for (key, value) in resp.headers().iter() { - http_string.push_str(&format!("{}: {}\r\n", key, value.to_str().unwrap())); +async fn shutdown_signal() { + tokio::signal::ctrl_c() + .await + .expect("Failed to install CTRL+C signal handler"); +} + +pub async fn run() -> Result<(), Box> { + // Server address + let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); + + // Create service + let make_svc = + make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(handle_request)) }); + + // Create server + let server = Server::bind(&addr).serve(make_svc); + + println!("HTTP Proxy Server running on http://{}", addr); + println!("Usage:"); + println!(" - Add 'Ghost-Route: https://target.com' header to route to specific server"); + println!(" - Without header, routes to default: {}", DEFAULT_TARGET); + println!("Press Ctrl+C to stop"); + + // Run server with graceful shutdown + let graceful = server.with_graceful_shutdown(shutdown_signal()); + + if let Err(e) = graceful.await { + eprintln!("Server error: {}", e); } - - http_string.push_str("\r\n"); - - let body = resp.text().unwrap(); - http_string.push_str(&body); - http_string + Ok(()) }