Temp commit before restructure
This commit is contained in:
Generated
+877
-8
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,6 @@ thiserror.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
smolmix-dns = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
tokio = { workspace = true, features = ["io-util", "macros", "rt-multi-thread", "time", "net"] }
|
||||
tokio-tungstenite.workspace = true
|
||||
webpki-roots.workspace = true
|
||||
@@ -46,8 +45,6 @@ reqwest = { workspace = true, features = ["rustls"] }
|
||||
chrono = { workspace = true }
|
||||
libp2p = { version = "0.56", features = ["tokio", "noise", "yamux", "ping", "macros"] }
|
||||
tokio-util = { workspace = true, features = ["compat"] }
|
||||
tokio-smoltcp = "0.5"
|
||||
tracing = { workspace = true }
|
||||
|
||||
[[example]]
|
||||
name = "websocket"
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
# smolmix
|
||||
|
||||
A TCP/UDP tunnel over the Nym mixnet. Uses smoltcp as a userspace network stack and connects to an Exit Gateway's IP Packet Router, so the exit IP is the gateway's — not yours.
|
||||
|
||||
`Tunnel` gives you standard `TcpStream` and `UdpSocket` types (from tokio-smoltcp) that work transparently with the async Rust ecosystem: tokio-rustls for TLS, hyper for HTTP, tokio-tungstenite for WebSockets, etc.
|
||||
|
||||
## Quick start
|
||||
|
||||
```rust
|
||||
use smolmix::Tunnel;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
let tunnel = Tunnel::new().await?;
|
||||
|
||||
// Raw TCP — works with any protocol
|
||||
let mut tcp = tunnel.tcp_connect("1.1.1.1:80".parse()?).await?;
|
||||
tcp.write_all(b"GET / HTTP/1.1\r\nHost: 1.1.1.1\r\nConnection: close\r\n\r\n").await?;
|
||||
|
||||
// Raw UDP — datagrams over the mixnet
|
||||
let udp = tunnel.udp_socket().await?;
|
||||
udp.send_to(&packet, "1.1.1.1:53".parse()?).await?;
|
||||
```
|
||||
|
||||
## Companion crates
|
||||
|
||||
For higher-level protocols, add the companion crates you need:
|
||||
|
||||
| Crate | What it provides |
|
||||
|-------|-----------------|
|
||||
| **smolmix** | `Tunnel`, `TcpStream`, `UdpSocket` (this crate) |
|
||||
| [smolmix-dns](../dns/) | `Resolver` newtype wrapping hickory-resolver |
|
||||
| [smolmix-tls](../tls/) | Shared `TlsConnector` and `connect()` with webpki roots |
|
||||
| [smolmix-hyper](../hyper/) | `Client` newtype wrapping hyper-util |
|
||||
| [smolmix-tungstenite](../tungstenite/) | `connect()` for WebSocket over TLS |
|
||||
| [smolmix-libp2p](../libp2p/) | `SmolmixTransport` implementing libp2p `Transport` |
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
smolmix = { workspace = true }
|
||||
smolmix-dns = { workspace = true } # DNS resolution
|
||||
smolmix-tls = { workspace = true } # TLS setup (used by hyper + tungstenite)
|
||||
smolmix-hyper = { workspace = true } # HTTP client
|
||||
smolmix-tungstenite = { workspace = true } # WebSocket client
|
||||
smolmix-libp2p = { workspace = true } # libp2p transport
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
All examples include a clearnet-vs-mixnet comparison with timing and accept `--ipr <ADDRESS>` for targeting a specific exit node.
|
||||
|
||||
```sh
|
||||
cargo run -p smolmix --example tcp # raw TCP connection
|
||||
cargo run -p smolmix --example udp # raw UDP datagram
|
||||
cargo run -p smolmix --example websocket # WebSocket over TLS (raw TcpStream composability)
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
See [`src/ARCHITECTURE.md`](src/ARCHITECTURE.md).
|
||||
@@ -64,7 +64,7 @@ async fn https_get(
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), BoxError> {
|
||||
smolmix::init_logging();
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
rustls::crypto::ring::default_provider()
|
||||
.install_default()
|
||||
.expect("Failed to install rustls crypto provider");
|
||||
|
||||
@@ -148,7 +148,7 @@ impl Transport for SmolmixTransport {
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), BoxError> {
|
||||
smolmix::init_logging();
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
|
||||
|
||||
+13
-2
@@ -1,17 +1,28 @@
|
||||
[package]
|
||||
name = "smolmix-dns"
|
||||
description = "DNS resolution through the Nym mixnet via hickory-resolver"
|
||||
version = "0.0.1"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
rust-version.workspace = true
|
||||
readme = "README.md"
|
||||
publish = true
|
||||
|
||||
[dependencies]
|
||||
smolmix = { workspace = true }
|
||||
hickory-proto = { workspace = true, features = ["tokio"] }
|
||||
hickory-resolver = { workspace = true, features = ["tokio"] }
|
||||
tokio-smoltcp = "0.5"
|
||||
tokio-smoltcp = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
# Clearnet baseline in example
|
||||
hickory-resolver = { workspace = true, features = ["tokio", "system-config"] }
|
||||
tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] }
|
||||
tracing = { workspace = true }
|
||||
nym-bin-common = { workspace = true, features = ["basic_tracing"] }
|
||||
|
||||
[[example]]
|
||||
name = "resolve"
|
||||
|
||||
@@ -18,7 +18,7 @@ type BoxError = Box<dyn std::error::Error + Send + Sync>;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), BoxError> {
|
||||
smolmix::init_logging();
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
|
||||
let domain = "example.com";
|
||||
|
||||
|
||||
@@ -1,25 +1,39 @@
|
||||
[package]
|
||||
name = "smolmix-hyper"
|
||||
description = "HTTP client routing all traffic through the Nym mixnet via hyper"
|
||||
version = "0.0.1"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
rust-version.workspace = true
|
||||
readme = "README.md"
|
||||
publish = true
|
||||
|
||||
[dependencies]
|
||||
smolmix = { workspace = true }
|
||||
smolmix-dns = { workspace = true }
|
||||
smolmix-tls = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
hyper = { workspace = true, features = ["client", "http1"] }
|
||||
hyper-util = { workspace = true, features = ["tokio", "client-legacy"] }
|
||||
http-body-util = { workspace = true }
|
||||
smolmix-tls = { workspace = true }
|
||||
tokio-smoltcp = "0.5"
|
||||
tokio-smoltcp = { workspace = true }
|
||||
pin-project-lite = "0.2"
|
||||
tower = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
# Clearnet baseline in example
|
||||
reqwest = { workspace = true }
|
||||
rustls = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] }
|
||||
tracing = { workspace = true }
|
||||
nym-bin-common = { workspace = true, features = ["basic_tracing"] }
|
||||
|
||||
[[example]]
|
||||
name = "get"
|
||||
|
||||
[[example]]
|
||||
name = "post"
|
||||
|
||||
@@ -15,7 +15,7 @@ type BoxError = Box<dyn std::error::Error + Send + Sync>;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), BoxError> {
|
||||
smolmix::init_logging();
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
rustls::crypto::ring::default_provider()
|
||||
.install_default()
|
||||
.expect("Failed to install rustls crypto provider");
|
||||
|
||||
@@ -27,7 +27,7 @@ const JSON_BODY: &str = r#"{"message": "hello from the Nym mixnet!"}"#;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), BoxError> {
|
||||
smolmix::init_logging();
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
rustls::crypto::ring::default_provider()
|
||||
.install_default()
|
||||
.expect("Failed to install rustls crypto provider");
|
||||
|
||||
+19
-2
@@ -1,11 +1,28 @@
|
||||
[package]
|
||||
name = "smolmix-tls"
|
||||
description = "TLS connector with webpki roots for smolmix tunneled connections"
|
||||
version = "0.0.1"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
rust-version.workspace = true
|
||||
readme = "README.md"
|
||||
publish = true
|
||||
|
||||
[dependencies]
|
||||
tokio-smoltcp = "0.5"
|
||||
tokio-rustls = "0.26"
|
||||
tokio-smoltcp = { workspace = true }
|
||||
tokio-rustls = { workspace = true }
|
||||
rustls = { workspace = true }
|
||||
webpki-roots = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
smolmix = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time", "net", "io-util"] }
|
||||
tracing = { workspace = true }
|
||||
nym-bin-common = { workspace = true, features = ["basic_tracing"] }
|
||||
|
||||
[[example]]
|
||||
name = "connect"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# smolmix-tls
|
||||
|
||||
Shared TLS setup for smolmix tunneled connections. Provides a pre-configured `TlsConnector` with webpki root certificates and convenience functions for TLS over `TcpStream`, used internally by `smolmix-hyper` and `smolmix-tungstenite`.
|
||||
Shared TLS setup for smolmix tunneled connections. Provides a pre-configured `TlsConnector` with webpki root certificates and convenience functions for TLS over `TcpStream`, used internally by `smolmix-hyper`.
|
||||
|
||||
## Quick start
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
//! TLS connection: clearnet vs Nym mixnet comparison.
|
||||
//!
|
||||
//! Performs a TLS handshake and HTTPS GET request via both clearnet (tokio-rustls
|
||||
//! over a system TCP socket) and the mixnet (smolmix-tls over a tunnel), then
|
||||
//! compares timing and verifies both see the same content.
|
||||
//!
|
||||
//! Run with:
|
||||
//! cargo run -p smolmix-tls --example connect
|
||||
//! cargo run -p smolmix-tls --example connect -- --ipr <IPR_ADDRESS>
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustls::ClientConfig;
|
||||
use smolmix::{Recipient, Tunnel};
|
||||
use smolmix_tls::{connect_with, connector};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tracing::info;
|
||||
|
||||
type BoxError = Box<dyn std::error::Error + Send + Sync>;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), BoxError> {
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
|
||||
rustls::crypto::ring::default_provider()
|
||||
.install_default()
|
||||
.expect("Failed to install rustls crypto provider");
|
||||
|
||||
let host = "example.com";
|
||||
let addr: std::net::SocketAddr = "93.184.216.34:443".parse()?;
|
||||
|
||||
// --- Clearnet baseline via tokio + tokio-rustls ---
|
||||
info!("Clearnet TLS connection to {host}...");
|
||||
let clearnet_start = tokio::time::Instant::now();
|
||||
|
||||
let mut root_store = rustls::RootCertStore::empty();
|
||||
root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
|
||||
let config = ClientConfig::builder()
|
||||
.with_root_certificates(root_store)
|
||||
.with_no_client_auth();
|
||||
let tls_connector = tokio_rustls::TlsConnector::from(Arc::new(config));
|
||||
|
||||
let tcp = tokio::net::TcpStream::connect(addr).await?;
|
||||
let server_name = rustls::pki_types::ServerName::try_from(host.to_string())?;
|
||||
let mut tls = tls_connector.connect(server_name, tcp).await?;
|
||||
|
||||
tls.write_all(
|
||||
format!("GET / HTTP/1.1\r\nHost: {host}\r\nConnection: close\r\n\r\n").as_bytes(),
|
||||
)
|
||||
.await?;
|
||||
let mut clearnet_buf = Vec::new();
|
||||
tls.read_to_end(&mut clearnet_buf).await?;
|
||||
let clearnet_duration = clearnet_start.elapsed();
|
||||
|
||||
let clearnet_status = String::from_utf8_lossy(&clearnet_buf[..40.min(clearnet_buf.len())]);
|
||||
info!(
|
||||
"Clearnet: {} bytes, status: {:?} ({:?})",
|
||||
clearnet_buf.len(),
|
||||
clearnet_status.lines().next().unwrap_or(""),
|
||||
clearnet_duration
|
||||
);
|
||||
|
||||
// --- Mixnet via smolmix-tls ---
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let ipr_addr = args
|
||||
.iter()
|
||||
.position(|a| a == "--ipr")
|
||||
.and_then(|i| args.get(i + 1));
|
||||
|
||||
let tunnel = if let Some(addr_str) = ipr_addr {
|
||||
let recipient: Recipient = addr_str.parse().expect("invalid IPR address");
|
||||
Tunnel::new_with_ipr(recipient).await?
|
||||
} else {
|
||||
Tunnel::new().await?
|
||||
};
|
||||
|
||||
let tls_conn = connector();
|
||||
|
||||
info!("Mixnet TLS connection to {host}...");
|
||||
let mixnet_start = tokio::time::Instant::now();
|
||||
|
||||
let tcp = tunnel.tcp_connect(addr).await?;
|
||||
let mut tls = connect_with(&tls_conn, tcp, host).await?;
|
||||
|
||||
tls.write_all(
|
||||
format!("GET / HTTP/1.1\r\nHost: {host}\r\nConnection: close\r\n\r\n").as_bytes(),
|
||||
)
|
||||
.await?;
|
||||
let mut mixnet_buf = Vec::new();
|
||||
tls.read_to_end(&mut mixnet_buf).await?;
|
||||
let mixnet_duration = mixnet_start.elapsed();
|
||||
|
||||
let mixnet_status = String::from_utf8_lossy(&mixnet_buf[..40.min(mixnet_buf.len())]);
|
||||
info!(
|
||||
"Mixnet: {} bytes, status: {:?} ({:?})",
|
||||
mixnet_buf.len(),
|
||||
mixnet_status.lines().next().unwrap_or(""),
|
||||
mixnet_duration
|
||||
);
|
||||
|
||||
// --- Compare ---
|
||||
info!("=== Results ===");
|
||||
info!(
|
||||
"Clearnet: {} bytes in {:?}",
|
||||
clearnet_buf.len(),
|
||||
clearnet_duration
|
||||
);
|
||||
info!(
|
||||
"Mixnet: {} bytes in {:?}",
|
||||
mixnet_buf.len(),
|
||||
mixnet_duration
|
||||
);
|
||||
|
||||
let slowdown = mixnet_duration.as_millis() as f64 / clearnet_duration.as_millis().max(1) as f64;
|
||||
info!("Slowdown: {slowdown:.1}x");
|
||||
|
||||
tunnel.shutdown().await;
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user