Clean readme, replace Arcs with leaked Boxes

This commit is contained in:
Pascal Engélibert 2026-03-17 11:12:44 +01:00
commit a95efd9ed8
4 changed files with 19 additions and 35 deletions

View file

@ -27,12 +27,13 @@ rustls-symcrypt = { version = "0.2.1", optional = true, features = ["chacha", "x
[features]
default = [
"aws-lc",
#"record",
"aws-lc",# Change this to the wanted cryptographic backend (list below)
"record",# It may be needed to remove the record feature when building with openssl
]
record = ["sslrelay"]
# Available cryptographic backends
aws-lc = ["tokio-rustls/aws-lc-rs", "rustls-post-quantum", "rustls-post-quantum/aws-lc-rs-unstable", "aws-lc-rs"]
boring = ["boring-rustls-provider"]
graviola = ["rustls-graviola"]

View file

@ -2,9 +2,7 @@
This program has two modes:
* recording proxy: relays trafic with or without TLS and record requests and responses in clear. It is a TLS termination thus a certificate is needed.
* trafic replay: run a client that sends the recorded requests, and a server that responds with the corresponding recorded responses. A proxy can be placed in between. The proxy can even alter the plain data, because the server uses hash distance to identify the requests.
It has been tested with HTTP trafic only. Other protocols which are not request/response (or even websocket) may not be recorded properly.
* trafic replay: run a client that sends the recorded requests, and a server that responds with the corresponding recorded responses. Responses are replaced with the same amount of random bytes for performance.
It relies on the server name extension in TLS (SNI). Requests without server name may not be recorded.
@ -12,27 +10,21 @@ For experimental purpose. Do not use on an open network where security matters.
## Build
[Install Rust nightly.](https://rustup.rs)
Choose a cryptographic backend in `Cargo.toml`.
```bash
RUSTFLAGS="--cfg tokio_unstable" cargo build --release
cargo build --release
```
## Record file format
The record file is a list of records. Each record follows this format:
* [1 byte] direction: ASCII 'C' for client-to-server, 'S' for server-to-client
* [8 bytes] connection id, big endian
* [1 byte] server name length
* server name (TLS's SNI or HTTP's Host)
* [8 bytes] data length, big endian
* data
## SSLKEYLOGFILE
The `SSLKEYLOGFILE` environment variable can be set to a file path to which the connection secrets will be exported, enabling decrypting the traffic in Wireshark.
## License
GNU AGPL v3, CopyLeft 2025 Pascal Engélibert [(why copyleft?)](https://txmn.tk/blog/why-copyleft/)
GNU AGPL v3, CopyLeft 2025-2026 Pascal Engélibert [(why copyleft?)](https://txmn.tk/blog/why-copyleft/)
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

View file

@ -102,25 +102,24 @@ pub async fn play(
) {
// Semaphore used to limit the number of concurrent clients.
// Its handle is released when the task panics.
let limiter = Arc::new(Semaphore::new(concurrency));
let counter = Arc::new(AtomicU32::new(0));
let running = Arc::new(Mutex::new(HashSet::new()));
let limiter: &'static _ = Box::leak(Box::new(Semaphore::new(concurrency)));
let counter: &'static _ = Box::leak(Box::new(AtomicU32::new(0)));
let running: &'static _ = Box::leak(Box::new(Mutex::new(HashSet::new())));
let total = records.len() * repeat as usize;
let connect_to = connect_to.to_socket_addrs().unwrap().next().unwrap();
let dummy_bytes = Arc::new(vec![0x42u8; 16 * 1024 * 1024]);
let dummy_bytes: &'static _ = Box::leak(Box::new(vec![0x42u8; 16 * 1024 * 1024]));
let notify_socket = notify_addr.map(|notify_addr| {
let socket = std::net::UdpSocket::bind("0.0.0.0:48567").unwrap();
socket.connect(notify_addr).unwrap();
Arc::new(socket)
let socket: &'static _ = Box::leak(Box::new(socket));
socket
});
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
tokio::spawn({
let running = running.clone();
let counter = counter.clone();
async move {
let mut last_count = 0;
loop {
@ -197,11 +196,7 @@ pub async fn play(
let mut handles = Vec::new();
for (conn_id, (server_name, records)) in records.iter() {
let connector = TlsConnector::from(config.clone());
let counter = counter.clone();
let limiter = limiter.clone();
let running = running.clone();
let dummy_bytes = dummy_bytes.clone();
let notify_socket = notify_socket.clone();
handles.push(tokio::spawn(async move {
let mut running_guard = running.lock().await;
running_guard.insert(*conn_id);
@ -294,11 +289,7 @@ pub async fn play(
for _i in 0..repeat {
let mut handles = Vec::new();
for (conn_id, (_server_name, records)) in records.iter() {
let counter = counter.clone();
let limiter = limiter.clone();
let running = running.clone();
let dummy_bytes = dummy_bytes.clone();
let notify_socket = notify_socket.clone();
handles.push(tokio::spawn(async move {
let mut running_guard = running.lock().await;
running_guard.insert(*conn_id);
@ -366,7 +357,7 @@ pub async fn play(
println!("Client: {} / {}", cnt, total);
}
drop(limiter);
if let Some(notify_socket) = &notify_socket {
if let Some(notify_socket) = notify_socket {
notify_socket.send(&cnt.to_be_bytes()).unwrap();
}
let mut running_guard = running.lock().await;

View file

@ -48,8 +48,8 @@ pub async fn play(
}
}
let response_map = Arc::new(response_map);
let dummy_bytes = Arc::new(vec![0x42u8; 16 * 1024 * 1024]);
let response_map: &'static _ = Box::leak(Box::new(response_map));
let dummy_bytes: &'static _ = Box::leak(Box::new(vec![0x42u8; 16 * 1024 * 1024]));
if use_tls {
let mut resolver = ResolvesServerCertUsingSni::new();