Working tls handshake
This commit is contained in:
Generated
+10
@@ -367,6 +367,7 @@ dependencies = [
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"tokio",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1754,6 +1755,15 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.2"
|
||||
|
||||
@@ -14,3 +14,4 @@ reqwest = { version = "0.12.23", features = ["blocking"] }
|
||||
|
||||
hyper = { version = "0.14", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
webpki-roots = "1.0.2"
|
||||
|
||||
+30
-5
@@ -1,14 +1,39 @@
|
||||
use std::io::{Read, Write};
|
||||
use std::{
|
||||
io::{Read, Write},
|
||||
net::TcpStream,
|
||||
};
|
||||
|
||||
pub mod server;
|
||||
pub mod tls;
|
||||
|
||||
pub fn request(gateway: &str, addr: &str) -> String {
|
||||
let (mut conn, mut tcp) = tls::mask_tls(gateway).unwrap();
|
||||
pub struct Request {
|
||||
host: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
pub fn new(url: &str) -> Self {
|
||||
Self {
|
||||
host: url.to_string(),
|
||||
path: String::from("/"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Request {
|
||||
pub fn send(&self) -> String {
|
||||
let mut tcp = TcpStream::connect((self.host.as_str(), 443)).unwrap();
|
||||
let mut conn = tls::tls13_handshake(&self.host, &mut tcp).unwrap();
|
||||
let mut tls = rustls::Stream::new(&mut conn, &mut tcp);
|
||||
tls.write_all(format!("ROUTE {addr}\nGET / HTTP/1.1").as_bytes())
|
||||
write!(
|
||||
tls,
|
||||
"GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\nUser-Agent: rustls/0.23\r\n\r\n",
|
||||
self.path, self.host
|
||||
)
|
||||
.unwrap();
|
||||
tls.flush().unwrap();
|
||||
let mut resp = Vec::new();
|
||||
tls.read_to_end(&mut resp).unwrap();
|
||||
String::from_utf8_lossy(&resp).to_string()
|
||||
String::from_utf8(resp).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
+5
-7
@@ -1,8 +1,6 @@
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
ghostnet_rs::server::run().await.unwrap();
|
||||
// println!(
|
||||
// "{}",
|
||||
// ghostnet_rs::request("ghostnet-rs.onrender.com:443", "https://wikipedia.org")
|
||||
// );
|
||||
use ghostnet_rs::Request;
|
||||
|
||||
fn main() {
|
||||
let req = Request::new("example.com");
|
||||
println!("{}", req.send());
|
||||
}
|
||||
|
||||
+6
-4
@@ -10,12 +10,13 @@ use tokio;
|
||||
const DEFAULT_TARGET: &str = "https://crackmes.one";
|
||||
const GHOST_ROUTE_HEADER: &str = "ghost-route";
|
||||
|
||||
async fn handle_request(req: Request<Body>) -> Result<Response<Body>, Infallible> {
|
||||
async fn handle_request(mut req: Request<Body>) -> Result<Response<Body>, Infallible> {
|
||||
let target_url = req
|
||||
.headers()
|
||||
.get(GHOST_ROUTE_HEADER)
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.unwrap_or(DEFAULT_TARGET);
|
||||
.unwrap_or(DEFAULT_TARGET)
|
||||
.to_string();
|
||||
|
||||
let url_params = req
|
||||
.uri()
|
||||
@@ -38,7 +39,7 @@ async fn handle_request(req: Request<Body>) -> Result<Response<Body>, Infallible
|
||||
(
|
||||
HeaderName::from_str("host").unwrap(),
|
||||
HeaderValue::from_bytes(
|
||||
reqwest::Url::from_str(target_url)
|
||||
reqwest::Url::from_str(&target_url)
|
||||
.unwrap()
|
||||
.host_str()
|
||||
.unwrap()
|
||||
@@ -54,7 +55,8 @@ async fn handle_request(req: Request<Body>) -> Result<Response<Body>, Infallible
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
));
|
||||
))
|
||||
.body(hyper::body::to_bytes(req.body_mut()).await.unwrap());
|
||||
|
||||
let response = builder.send().await.unwrap();
|
||||
|
||||
|
||||
+73
-21
@@ -1,27 +1,79 @@
|
||||
use rustls::ClientConfig;
|
||||
use rustls::client::ClientConnection;
|
||||
use std::{net::TcpStream, sync::Arc};
|
||||
use std::net::TcpStream;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn mask_tls<'a>(
|
||||
addr: &str,
|
||||
) -> Result<(ClientConnection, TcpStream), Box<dyn std::error::Error>> {
|
||||
let certs = rustls_native_certs::load_native_certs()
|
||||
.expect("could not load platform certificate store");
|
||||
let mut root_store = rustls::RootCertStore::empty();
|
||||
for cert in certs {
|
||||
root_store.add(cert).unwrap();
|
||||
use rustls::client::ClientConfig;
|
||||
use rustls::pki_types::ServerName;
|
||||
use rustls::{ClientConnection, RootCertStore};
|
||||
|
||||
pub fn root_store() -> RootCertStore {
|
||||
// Prefer system roots (works on most OSes). If that fails, fall back to webpki-roots.
|
||||
let mut store = RootCertStore::empty();
|
||||
|
||||
// Try load native (ignore per-cert errors, just skip bad ones)
|
||||
for cert in rustls_native_certs::load_native_certs().certs {
|
||||
let _ = store.add(cert);
|
||||
}
|
||||
|
||||
// Build TLS client config
|
||||
let config = ClientConfig::builder()
|
||||
.with_root_certificates(root_store)
|
||||
if store.is_empty() {
|
||||
// Fallback: baked-in Mozilla roots via webpki-roots
|
||||
store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
|
||||
}
|
||||
|
||||
store
|
||||
}
|
||||
|
||||
pub fn tls13_config() -> Arc<ClientConfig> {
|
||||
let mut cfg = ClientConfig::builder()
|
||||
.with_root_certificates(root_store())
|
||||
.with_no_client_auth();
|
||||
|
||||
let arc_cfg = Arc::new(config);
|
||||
let conn = ClientConnection::new(
|
||||
arc_cfg,
|
||||
addr.split_once(":").unwrap().0.to_string().try_into()?,
|
||||
)?;
|
||||
let tcp = TcpStream::connect(addr)?;
|
||||
Ok((conn, tcp))
|
||||
// ALPN (optional but typical)
|
||||
cfg.alpn_protocols = vec![b"http/1.1".to_vec()];
|
||||
|
||||
// Pin to TLS 1.3 only
|
||||
// cfg.versions = vec![rustls::version::TLS13];
|
||||
|
||||
Arc::new(cfg)
|
||||
}
|
||||
|
||||
pub fn tls13_handshake(
|
||||
host: &str,
|
||||
tcp: &mut TcpStream,
|
||||
) -> Result<ClientConnection, Box<dyn std::error::Error>> {
|
||||
// SNI + config
|
||||
let server_name = ServerName::try_from(host.to_string())?;
|
||||
let mut conn = ClientConnection::new(tls13_config(), server_name)?;
|
||||
|
||||
// Drive the handshake to completion (blocking)
|
||||
while conn.is_handshaking() {
|
||||
// complete_io performs any pending write(s) and then tries to read.
|
||||
// It returns Ok((nw, nr)) when some I/O happened; errors propagate.
|
||||
let _ = conn.complete_io(tcp)?;
|
||||
}
|
||||
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
// fn main() -> anyhow::Result<()> {
|
||||
// let host = "example.com";
|
||||
|
||||
// // 1) TLS 1.3 handshake over a TcpStream
|
||||
// let (mut conn, mut tcp) = tls13_handshake(host, 443)?;
|
||||
|
||||
// // 2) After handshake, you can wrap into a rustls::Stream to do Read/Write of app data
|
||||
// let mut tls = rustls::Stream::new(&mut conn, &mut tcp);
|
||||
|
||||
// // Simple HTTP/1.1 GET (for demonstration)
|
||||
// write!(
|
||||
// tls,
|
||||
// "GET / HTTP/1.1\r\nHost: {host}\r\nConnection: close\r\nUser-Agent: rustls/0.23\r\n\r\n"
|
||||
// )?;
|
||||
// tls.flush()?;
|
||||
|
||||
// // Read response
|
||||
// let mut resp = Vec::new();
|
||||
// tls.read_to_end(&mut resp)?;
|
||||
// println!("{}", String::from_utf8_lossy(&resp));
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user