Compare commits
10
Commits
ced153a180
...
7aefdbcc40
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7aefdbcc40 | ||
|
|
53449db7c6 | ||
|
|
1800f2acea | ||
|
|
cf9479cda2 | ||
|
|
506d57e6f9 | ||
|
|
92bfad7f5e | ||
|
|
918898558a | ||
|
|
fa985a69c5 | ||
|
|
95b20dae76 | ||
|
|
0c3873c1d4 |
Generated
+10
@@ -182,6 +182,7 @@ version = "0.0.1-alpha"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-native-certs",
|
"rustls-native-certs",
|
||||||
|
"webpki-roots",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -518,6 +519,15 @@ dependencies = [
|
|||||||
"wit-bindgen-rt",
|
"wit-bindgen-rt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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"
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ name = "ghostnet-rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
rustls = "0.23.31"
|
rustls = "0.23.31"
|
||||||
rustls-native-certs = "0.8.1"
|
rustls-native-certs = "0.8.1"
|
||||||
|
webpki-roots = "1.0.2"
|
||||||
|
|||||||
@@ -24,4 +24,10 @@ A router manages the clients and routes messages from one client to another to e
|
|||||||
|
|
||||||
## Todo
|
## Todo
|
||||||
- End-To-End Encryption
|
- End-To-End Encryption
|
||||||
- Mask the communications like **HTTPS**
|
- Mask the communications like **HTTPS**
|
||||||
|
|
||||||
|
## Common install issues on linux
|
||||||
|
```bash
|
||||||
|
sudo apt install pkg-config -y
|
||||||
|
sudo apt install libssl-dev -y
|
||||||
|
```
|
||||||
+126
-1
@@ -1,3 +1,128 @@
|
|||||||
|
use std::{
|
||||||
|
io::{Read, Write},
|
||||||
|
net::TcpStream,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Method {
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Delete,
|
||||||
|
Head,
|
||||||
|
Options,
|
||||||
|
Patch,
|
||||||
|
Connect,
|
||||||
|
Trace,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod server;
|
||||||
pub mod tls;
|
pub mod tls;
|
||||||
|
|
||||||
pub fn request(gateway: &str) {}
|
#[derive(Debug)]
|
||||||
|
pub struct Request {
|
||||||
|
host: String,
|
||||||
|
path: String,
|
||||||
|
method: Method,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request {
|
||||||
|
pub fn new(url: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
host: url.to_string(),
|
||||||
|
path: String::from("/"),
|
||||||
|
method: Method::Get,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_str(host: &str, req: &str) -> Self {
|
||||||
|
let first_line = req.lines().next().unwrap_or_default();
|
||||||
|
let mut parts = first_line.split_whitespace();
|
||||||
|
let method = parts.next().unwrap_or_default();
|
||||||
|
let path = parts.next().unwrap_or("/");
|
||||||
|
|
||||||
|
Self {
|
||||||
|
host: host.to_string(),
|
||||||
|
path: path.to_string(),
|
||||||
|
method: match method {
|
||||||
|
"GET" => Method::Get,
|
||||||
|
"POST" => Method::Post,
|
||||||
|
"PUT" => Method::Put,
|
||||||
|
"DELETE" => Method::Delete,
|
||||||
|
"HEAD" => Method::Head,
|
||||||
|
"OPTIONS" => Method::Options,
|
||||||
|
"PATCH" => Method::Patch,
|
||||||
|
"CONNECT" => Method::Connect,
|
||||||
|
"TRACE" => Method::Trace,
|
||||||
|
_ => Method::Get,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request {
|
||||||
|
pub fn send_bytes(&self) -> Vec<u8> {
|
||||||
|
let tcp = TcpStream::connect((self.host.as_str(), 443)).unwrap();
|
||||||
|
send_request(tcp, &self.host, &self.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(&self) -> String {
|
||||||
|
let tcp = TcpStream::connect((self.host.as_str(), 443)).unwrap();
|
||||||
|
String::from_utf8(send_request(tcp, &self.host, &self.to_string())).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_routed(&self, router: &str) -> String {
|
||||||
|
let mut tcp = TcpStream::connect(router).unwrap();
|
||||||
|
tcp.write_all(format!("ROUTE {}:443", self.host).as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
tcp.read(&mut [0; 32]).unwrap();
|
||||||
|
String::from_utf8(send_request(tcp, &self.host, &self.to_string())).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_routed_secure(&self, router: &str) -> String {
|
||||||
|
let tcp = TcpStream::connect((router, 443)).unwrap();
|
||||||
|
send_request(
|
||||||
|
tcp.try_clone().unwrap(),
|
||||||
|
&router,
|
||||||
|
&format!("ROUTE {}:443", self.host),
|
||||||
|
);
|
||||||
|
String::from_utf8(send_request(tcp, &self.host, &self.to_string())).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"{} {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\nUser-Agent: rustls/0.23\r\n\r\n",
|
||||||
|
self.method, self.path, self.host
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_request(mut stream: TcpStream, host: &str, send: &str) -> Vec<u8> {
|
||||||
|
let mut conn = tls::tls13_handshake(&host, &mut stream).unwrap();
|
||||||
|
let mut tls = rustls::Stream::new(&mut conn, &mut stream);
|
||||||
|
tls.write_all(send.as_bytes()).unwrap();
|
||||||
|
tls.flush().unwrap();
|
||||||
|
let mut resp = Vec::new();
|
||||||
|
tls.read_to_end(&mut resp).unwrap();
|
||||||
|
resp
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Method {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
Self::Get => "GET",
|
||||||
|
Self::Post => "POST",
|
||||||
|
Self::Put => "PUT",
|
||||||
|
Self::Delete => "DELETE",
|
||||||
|
Self::Head => "HEAD",
|
||||||
|
Self::Options => "OPTIONS",
|
||||||
|
Self::Patch => "PATCH",
|
||||||
|
Self::Connect => "CONNECT",
|
||||||
|
Self::Trace => "TRACE",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+5
-14
@@ -1,16 +1,7 @@
|
|||||||
use std::io::{Read, Write};
|
|
||||||
|
|
||||||
use ghostnet_rs::tls;
|
|
||||||
use rustls::Stream;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let (mut conn, mut tcp) = tls::mask_tls("github.com").unwrap();
|
ghostnet_rs::server::run();
|
||||||
let mut tls = Stream::new(&mut conn, &mut tcp);
|
// println!(
|
||||||
|
// "{}",
|
||||||
tls.write_all("GET / HTTP/1.0\r\nHost: github.com\r\n\r\n".as_bytes())
|
// ghostnet_rs::Request::new("example.com").send_routed("localhost:6930")
|
||||||
.unwrap();
|
// );
|
||||||
|
|
||||||
let mut resp = Vec::new();
|
|
||||||
tls.read_to_end(&mut resp).unwrap();
|
|
||||||
println!("{}", String::from_utf8_lossy(&resp));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
use std::{
|
||||||
|
io::{Read, Write},
|
||||||
|
net::{TcpListener, TcpStream},
|
||||||
|
};
|
||||||
|
|
||||||
|
const DEFAULT_HOST: &str = "osui.netlify.app";
|
||||||
|
|
||||||
|
pub fn run() {
|
||||||
|
let server = TcpListener::bind(format!(
|
||||||
|
"0.0.0.0:{}",
|
||||||
|
std::env::var("PORT").unwrap_or("6930".to_string())
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
for stream in server.incoming() {
|
||||||
|
match stream {
|
||||||
|
Ok(mut client) => {
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
println!("Client connected");
|
||||||
|
let mut buf = [0; 1024];
|
||||||
|
|
||||||
|
let buf_len = client.read(&mut buf).unwrap();
|
||||||
|
|
||||||
|
let req = String::from_utf8_lossy(&buf[..buf_len]);
|
||||||
|
let req = req.lines().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if req.len() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if req[0].starts_with("ROUTE") {
|
||||||
|
println!("Route mode");
|
||||||
|
let addr = req[0].split_once(' ').unwrap().1;
|
||||||
|
println!("Connecting to {addr}");
|
||||||
|
let mut target = TcpStream::connect(addr).unwrap();
|
||||||
|
let mut target_t = target.try_clone().unwrap();
|
||||||
|
let mut client_t = client.try_clone().unwrap();
|
||||||
|
println!("Connected to {addr}");
|
||||||
|
client.write_all("CONN EST".as_bytes()).unwrap();
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
loop {
|
||||||
|
let mut buf = [0; 2048];
|
||||||
|
let buf_len = client_t.read(&mut buf).unwrap();
|
||||||
|
if buf_len == 0 {
|
||||||
|
target_t.shutdown(std::net::Shutdown::Both).unwrap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
target_t.write_all(&buf[..buf_len]).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut buf = [0; 2048];
|
||||||
|
let buf_len = target.read(&mut buf).unwrap();
|
||||||
|
if buf_len == 0 {
|
||||||
|
client.shutdown(std::net::Shutdown::Both).unwrap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
client.write_all(&buf[..buf_len]).unwrap();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let req = crate::Request::from_str(
|
||||||
|
DEFAULT_HOST,
|
||||||
|
&String::from_utf8_lossy(&buf[..buf_len]),
|
||||||
|
);
|
||||||
|
client.write_all(&req.send_bytes()).unwrap();
|
||||||
|
client.flush().unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+73
-19
@@ -1,25 +1,79 @@
|
|||||||
use rustls::ClientConfig;
|
use std::net::TcpStream;
|
||||||
use rustls::client::ClientConnection;
|
use std::sync::Arc;
|
||||||
use rustls_native_certs;
|
|
||||||
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(arc_cfg, addr.to_owned().try_into()?)?;
|
cfg.alpn_protocols = vec![b"http/1.1".to_vec()];
|
||||||
let tcp = TcpStream::connect(addr.to_owned() + ":443")?;
|
|
||||||
Ok((conn, tcp))
|
// 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