Working tls handshake
This commit is contained in:
Generated
+10
@@ -367,6 +367,7 @@ dependencies = [
|
|||||||
"rustls",
|
"rustls",
|
||||||
"rustls-native-certs",
|
"rustls-native-certs",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"webpki-roots",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1754,6 +1755,15 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"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]]
|
[[package]]
|
||||||
name = "which"
|
name = "which"
|
||||||
version = "4.4.2"
|
version = "4.4.2"
|
||||||
|
|||||||
@@ -14,3 +14,4 @@ reqwest = { version = "0.12.23", features = ["blocking"] }
|
|||||||
|
|
||||||
hyper = { version = "0.14", features = ["full"] }
|
hyper = { version = "0.14", features = ["full"] }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
webpki-roots = "1.0.2"
|
||||||
|
|||||||
+33
-8
@@ -1,14 +1,39 @@
|
|||||||
use std::io::{Read, Write};
|
use std::{
|
||||||
|
io::{Read, Write},
|
||||||
|
net::TcpStream,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod tls;
|
pub mod tls;
|
||||||
|
|
||||||
pub fn request(gateway: &str, addr: &str) -> String {
|
pub struct Request {
|
||||||
let (mut conn, mut tcp) = tls::mask_tls(gateway).unwrap();
|
host: String,
|
||||||
let mut tls = rustls::Stream::new(&mut conn, &mut tcp);
|
path: String,
|
||||||
tls.write_all(format!("ROUTE {addr}\nGET / HTTP/1.1").as_bytes())
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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();
|
.unwrap();
|
||||||
let mut resp = Vec::new();
|
tls.flush().unwrap();
|
||||||
tls.read_to_end(&mut resp).unwrap();
|
let mut resp = Vec::new();
|
||||||
String::from_utf8_lossy(&resp).to_string()
|
tls.read_to_end(&mut resp).unwrap();
|
||||||
|
String::from_utf8(resp).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-7
@@ -1,8 +1,6 @@
|
|||||||
#[tokio::main]
|
use ghostnet_rs::Request;
|
||||||
async fn main() {
|
|
||||||
ghostnet_rs::server::run().await.unwrap();
|
fn main() {
|
||||||
// println!(
|
let req = Request::new("example.com");
|
||||||
// "{}",
|
println!("{}", req.send());
|
||||||
// ghostnet_rs::request("ghostnet-rs.onrender.com:443", "https://wikipedia.org")
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -10,12 +10,13 @@ use tokio;
|
|||||||
const DEFAULT_TARGET: &str = "https://crackmes.one";
|
const DEFAULT_TARGET: &str = "https://crackmes.one";
|
||||||
const GHOST_ROUTE_HEADER: &str = "ghost-route";
|
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
|
let target_url = req
|
||||||
.headers()
|
.headers()
|
||||||
.get(GHOST_ROUTE_HEADER)
|
.get(GHOST_ROUTE_HEADER)
|
||||||
.and_then(|v| v.to_str().ok())
|
.and_then(|v| v.to_str().ok())
|
||||||
.unwrap_or(DEFAULT_TARGET);
|
.unwrap_or(DEFAULT_TARGET)
|
||||||
|
.to_string();
|
||||||
|
|
||||||
let url_params = req
|
let url_params = req
|
||||||
.uri()
|
.uri()
|
||||||
@@ -38,7 +39,7 @@ async fn handle_request(req: Request<Body>) -> Result<Response<Body>, Infallible
|
|||||||
(
|
(
|
||||||
HeaderName::from_str("host").unwrap(),
|
HeaderName::from_str("host").unwrap(),
|
||||||
HeaderValue::from_bytes(
|
HeaderValue::from_bytes(
|
||||||
reqwest::Url::from_str(target_url)
|
reqwest::Url::from_str(&target_url)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.host_str()
|
.host_str()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -54,7 +55,8 @@ async fn handle_request(req: Request<Body>) -> Result<Response<Body>, Infallible
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
));
|
))
|
||||||
|
.body(hyper::body::to_bytes(req.body_mut()).await.unwrap());
|
||||||
|
|
||||||
let response = builder.send().await.unwrap();
|
let response = builder.send().await.unwrap();
|
||||||
|
|
||||||
|
|||||||
+73
-21
@@ -1,27 +1,79 @@
|
|||||||
use rustls::ClientConfig;
|
use std::net::TcpStream;
|
||||||
use rustls::client::ClientConnection;
|
use std::sync::Arc;
|
||||||
use std::{net::TcpStream, sync::Arc};
|
|
||||||
|
|
||||||
pub fn mask_tls<'a>(
|
use rustls::client::ClientConfig;
|
||||||
addr: &str,
|
use rustls::pki_types::ServerName;
|
||||||
) -> Result<(ClientConnection, TcpStream), Box<dyn std::error::Error>> {
|
use rustls::{ClientConnection, RootCertStore};
|
||||||
let certs = rustls_native_certs::load_native_certs()
|
|
||||||
.expect("could not load platform certificate store");
|
pub fn root_store() -> RootCertStore {
|
||||||
let mut root_store = rustls::RootCertStore::empty();
|
// Prefer system roots (works on most OSes). If that fails, fall back to webpki-roots.
|
||||||
for cert in certs {
|
let mut store = RootCertStore::empty();
|
||||||
root_store.add(cert).unwrap();
|
|
||||||
|
// 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
|
if store.is_empty() {
|
||||||
let config = ClientConfig::builder()
|
// Fallback: baked-in Mozilla roots via webpki-roots
|
||||||
.with_root_certificates(root_store)
|
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();
|
.with_no_client_auth();
|
||||||
|
|
||||||
let arc_cfg = Arc::new(config);
|
// ALPN (optional but typical)
|
||||||
let conn = ClientConnection::new(
|
cfg.alpn_protocols = vec![b"http/1.1".to_vec()];
|
||||||
arc_cfg,
|
|
||||||
addr.split_once(":").unwrap().0.to_string().try_into()?,
|
// Pin to TLS 1.3 only
|
||||||
)?;
|
// cfg.versions = vec![rustls::version::TLS13];
|
||||||
let tcp = TcpStream::connect(addr)?;
|
|
||||||
Ok((conn, tcp))
|
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