modified: Cargo.lock

modified:   Cargo.toml
	new file:   src/dht.rs
	modified:   src/main.rs
	new file:   src/tor.rs
	new file:   src/tor_axum.rs
This commit is contained in:
Michael Wain 2025-03-09 20:19:45 +03:00
parent 0e0371f4da
commit 8cf177407c
6 changed files with 555 additions and 72 deletions

289
Cargo.lock generated
View File

@ -7,9 +7,23 @@ name = "Gamal"
version = "0.1.0"
dependencies = [
"arti-client",
"axum",
"bincode",
"env_logger",
"futures",
"futures-util",
"hyper",
"hyper-util",
"log",
"pin-project-lite",
"rusqlite",
"serde",
"sha3",
"tokio",
"tor-cell",
"tor-hsservice",
"tor-proto",
"tower-service",
]
[[package]]
@ -219,7 +233,6 @@ dependencies = [
"tor-netdoc",
"tor-persist",
"tor-proto",
"tor-ptmgr",
"tor-rtcompat",
"tracing",
"void",
@ -357,6 +370,61 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "axum"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
dependencies = [
"async-trait",
"axum-core",
"bytes",
"futures-util",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"rustversion",
"serde",
"serde_json",
"serde_path_to_error",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "axum-core"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http",
"http-body",
"http-body-util",
"mime",
"pin-project-lite",
"rustversion",
"sync_wrapper",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "backtrace"
version = "0.3.74"
@ -390,6 +458,15 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -829,7 +906,7 @@ dependencies = [
"proc-macro2",
"quote",
"sha3",
"strum 0.27.1",
"strum",
"syn 2.0.99",
"void",
]
@ -847,7 +924,7 @@ dependencies = [
"proc-macro2",
"quote",
"sha3",
"strum 0.27.1",
"strum",
"syn 2.0.99",
"void",
]
@ -1526,6 +1603,29 @@ dependencies = [
"itoa",
]
[[package]]
name = "http-body"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http",
]
[[package]]
name = "http-body-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
dependencies = [
"bytes",
"futures-util",
"http",
"http-body",
"pin-project-lite",
]
[[package]]
name = "httparse"
version = "1.10.1"
@ -1554,6 +1654,41 @@ dependencies = [
"serde",
]
[[package]]
name = "hyper"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"smallvec",
"tokio",
]
[[package]]
name = "hyper-util"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
dependencies = [
"bytes",
"futures-util",
"http",
"http-body",
"hyper",
"pin-project-lite",
"tokio",
"tower-service",
]
[[package]]
name = "iana-time-zone"
version = "0.1.61"
@ -1919,6 +2054,7 @@ version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
dependencies = [
"cc",
"pkg-config",
"vcpkg",
]
@ -1960,6 +2096,12 @@ dependencies = [
"regex-automata 0.1.10",
]
[[package]]
name = "matchit"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
[[package]]
name = "memchr"
version = "2.7.4"
@ -1987,6 +2129,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@ -2487,9 +2635,9 @@ dependencies = [
[[package]]
name = "priority-queue"
version = "2.1.2"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090ded312ed32a928fb49cb91ab4db6523ae3767225e61fbf6ceaaec3664ed26"
checksum = "35d34aad26c181c38e0399695bb8cd445c65222e40f68bebfea809650eb3eda6"
dependencies = [
"autocfg",
"equivalent",
@ -2896,6 +3044,16 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_path_to_error"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
dependencies = [
"itoa",
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.8"
@ -2905,6 +3063,18 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
version = "3.12.0"
@ -3153,16 +3323,7 @@ version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
dependencies = [
"strum_macros 0.26.4",
]
[[package]]
name = "strum"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
dependencies = [
"strum_macros 0.27.1",
"strum_macros",
]
[[package]]
@ -3178,19 +3339,6 @@ dependencies = [
"syn 2.0.99",
]
[[package]]
name = "strum_macros"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.99",
]
[[package]]
name = "subtle"
version = "2.6.1"
@ -3219,6 +3367,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
[[package]]
name = "synstructure"
version = "0.13.1"
@ -3353,9 +3507,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.43.0"
version = "1.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
checksum = "9975ea0f48b5aa3972bf2d888c238182458437cc2a19374b81b25cdf1023fb3a"
dependencies = [
"backtrace",
"bytes",
@ -3645,7 +3799,7 @@ dependencies = [
"serde",
"serde-value",
"serde_ignored",
"strum 0.26.3",
"strum",
"thiserror 2.0.12",
"toml",
"tor-basic-utils",
@ -3741,7 +3895,7 @@ dependencies = [
"scopeguard",
"serde",
"signature",
"strum 0.26.3",
"strum",
"thiserror 2.0.12",
"time",
"tor-async-utils",
@ -3774,7 +3928,7 @@ dependencies = [
"paste",
"retry-error",
"static_assertions",
"strum 0.26.3",
"strum",
"thiserror 2.0.12",
"tracing",
"void",
@ -3815,7 +3969,7 @@ dependencies = [
"rand",
"safelog",
"serde",
"strum 0.26.3",
"strum",
"thiserror 2.0.12",
"tor-async-utils",
"tor-basic-utils",
@ -3827,7 +3981,6 @@ dependencies = [
"tor-netdoc",
"tor-persist",
"tor-proto",
"tor-protover",
"tor-relay-selection",
"tor-rtcompat",
"tor-units",
@ -3853,7 +4006,7 @@ dependencies = [
"retry-error",
"safelog",
"slotmap-careful",
"strum 0.26.3",
"strum",
"thiserror 2.0.12",
"tor-async-utils",
"tor-basic-utils",
@ -3937,7 +4090,7 @@ dependencies = [
"safelog",
"serde",
"serde_with",
"strum 0.26.3",
"strum",
"thiserror 2.0.12",
"tor-async-utils",
"tor-basic-utils",
@ -4040,7 +4193,7 @@ dependencies = [
"safelog",
"serde",
"serde_with",
"strum 0.26.3",
"strum",
"thiserror 2.0.12",
"tor-basic-utils",
"tor-bytes",
@ -4146,7 +4299,7 @@ dependencies = [
"rand",
"serde",
"static_assertions",
"strum 0.26.3",
"strum",
"thiserror 2.0.12",
"time",
"tor-basic-utils",
@ -4300,33 +4453,6 @@ dependencies = [
"thiserror 2.0.12",
]
[[package]]
name = "tor-ptmgr"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65a49254c95ab7c39bf626c595bb583894bae3437d5e33b75ebf40f53ae4f9b4"
dependencies = [
"async-trait",
"cfg-if",
"derive_builder_fork_arti",
"fs-mistrust",
"futures",
"itertools",
"oneshot-fused-workaround",
"serde",
"thiserror 2.0.12",
"tor-async-utils",
"tor-basic-utils",
"tor-chanmgr",
"tor-config",
"tor-config-path",
"tor-error",
"tor-linkspec",
"tor-rtcompat",
"tor-socksproto",
"tracing",
]
[[package]]
name = "tor-relay-selection"
version = "0.28.0"
@ -4387,7 +4513,7 @@ dependencies = [
"pin-project",
"priority-queue",
"slotmap-careful",
"strum 0.26.3",
"strum",
"thiserror 2.0.12",
"tor-error",
"tor-general-addr",
@ -4426,12 +4552,41 @@ dependencies = [
"tor-memquota",
]
[[package]]
name = "tower"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper",
"tokio",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",

View File

@ -4,7 +4,22 @@ version = "0.1.0"
edition = "2021"
[dependencies]
arti-client = { version = "0.28.0", features = ["onion-service-client", "onion-service-service", "pt-client"] }
rusqlite = { version = "0.32.0", features = ["bundled"] }
tokio = { version = "1", features = ["full"] }
env_logger = "0.11.6"
log = "0.4.20"
sha3 = "0.10.8"
serde = { version = "1", features = ["derive"] }
bincode = "1.3.3"
tor-cell = "0.28.0"
tor-hsservice = "0.28.0"
tor-proto = { version = "0.28.0", features = ["hs-service", "tokio"] }
arti-client = { version = "0.28.0", features = ["tokio", "onion-service-service"]}
futures = "0.3"
axum = "0.7.5"
futures-util = "0.3.30"
hyper = "1.4.1"
hyper-util = { version = "0.1.6", features = ["service"] }
pin-project-lite = "0.2.14"
tower-service = "0.3.2"
hypertor = "0.1"

53
src/dht.rs Normal file
View File

@ -0,0 +1,53 @@
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
use serde::{Deserialize, Serialize};
use tokio::{net::UdpSocket, sync::{mpsc, Mutex}, task};
#[derive(Serialize, Deserialize, Debug)]
enum DHTMessage {
Put { key: String, value: String },
Get { key: String },
Response { value: Option<String> },
}
async fn server() {
let addr = "127.0.0.1:8080"; // Change this per node
let socket = UdpSocket::bind(addr).await.unwrap();
let storage = Arc::new(Mutex::new(HashMap::new()));
let (tx, mut rx) = mpsc::channel::<(SocketAddr, DHTMessage)>(100);
let storage_clone = storage.clone();
task::spawn(async move {
while let Some((peer, msg)) = rx.recv().await {
let response = match msg {
DHTMessage::Put { key, value } => {
storage_clone.lock().await.insert(key.clone(), value.clone());
DHTMessage::Response { value: Some("OK".to_string()) }
}
DHTMessage::Get { key } => {
let value = storage_clone.lock().await.get(&key).cloned();
DHTMessage::Response { value }
}
_ => DHTMessage::Response { value: None },
};
let response_bytes = bincode::serialize(&response).unwrap();
socket.send_to(&response_bytes, peer).await.unwrap();
}
});
/*let mut buf = [0; 1024];
loop {
let (size, peer) = socket.recv_from(&mut buf).await.unwrap();
if let Ok(msg) = bincode::deserialize::<DHTMessage>(&buf[..size]) {
tx.send((peer, msg)).await.unwrap();
}
}*/
}

View File

@ -1,9 +1,18 @@
use arti_client::{config::onion_service::OnionServiceConfigBuilder, TorClient, TorClientConfig};
use log::info;
use env_logger::Builder;
use log::{info, LevelFilter};
//mod dht;
mod tor_axum;
mod tor;
#[tokio::main]
async fn main() {
let config = TorClientConfig::default();
Builder::new()
.filter(None, LevelFilter::Debug)
.init();
/* let config = TorClientConfig::default();
if let Ok(tor_client) = TorClient::create_bootstrapped(config).await {
info!("Bootstrapped");
let onion_service_config = OnionServiceConfigBuilder::default().build().unwrap();
@ -12,5 +21,6 @@ async fn main() {
}
} else {
info!("Error with bootstrapping");
}
} */
tor::start().await;
}

32
src/tor.rs Normal file
View File

@ -0,0 +1,32 @@
use std::{error::Error, net::TcpListener};
use arti_client::{TorClient, TorClientConfig};
use futures::{Stream, StreamExt};
use log::info;
use tokio::io::split;
use tor_hsservice::config::OnionServiceConfigBuilder;
use tor_hsservice::handle_rend_requests;
use axum::{routing, Router};
use crate::tor_axum;
pub async fn start() -> Result<(), Box<dyn Error>> {
let tor_client = TorClient::create_bootstrapped(TorClientConfig::default()).await?;
let (onion_service, rend_requests) = tor_client.launch_onion_service(
OnionServiceConfigBuilder::default()
.nickname("gamal-service".to_owned().try_into().unwrap())
.build()?,
)?;
let stream_requests = handle_rend_requests(rend_requests);
let app = Router::new().route("/", routing::get(|| async { "Hello, World!" }));
println!("serving at: http://{}", onion_service.onion_name().unwrap());
tor_axum::serve(stream_requests, app).await;
Ok(())
}

218
src/tor_axum.rs Normal file
View File

@ -0,0 +1,218 @@
use std::{
convert::Infallible,
future::{
poll_fn,
Future,
IntoFuture,
},
marker::PhantomData,
pin::Pin,
task::{
Context,
Poll,
},
};
use axum::{
body::Body,
extract::Request,
response::Response,
Router,
};
use futures_util::{
future::{
BoxFuture,
FutureExt,
},
stream::{
BoxStream,
Stream,
StreamExt,
},
};
use hyper::body::Incoming;
use hyper_util::{
rt::{
TokioExecutor,
TokioIo,
},
server::conn::auto::Builder,
service::TowerToHyperService,
};
use log::error;
use tor_cell::relaycell::msg::Connected;
use tor_hsservice::StreamRequest;
use tor_proto::stream::{
DataStream,
IncomingStreamRequest,
};
use tower_service::Service;
/// Serve the service with the supplied stream requests.
///
/// See the [crate documentation](`crate`) for an example.
pub fn serve<M, S>(
stream_requests: impl Stream<Item = StreamRequest> + Send + 'static,
make_service: M,
) -> Serve<M, S>
where
M: for<'a> Service<IncomingStream<'a>, Error = Infallible, Response = S>,
S: Service<Request, Error = Infallible, Response = Response>,
{
Serve {
stream_requests: stream_requests.boxed(),
make_service,
_marker: PhantomData,
}
}
/// Future returned by [`serve`].
pub struct Serve<M, S> {
stream_requests: BoxStream<'static, StreamRequest>,
make_service: M,
_marker: PhantomData<S>,
}
impl<M, S> IntoFuture for Serve<M, S>
where
M: for<'a> Service<IncomingStream<'a>, Error = Infallible, Response = S> + Send + 'static,
for<'a> <M as Service<IncomingStream<'a>>>::Future: Send,
S: Service<Request, Response = Response, Error = Infallible> + Clone + Send + 'static,
S::Future: Send,
{
type Output = ();
type IntoFuture = private::ServeFuture;
fn into_future(mut self) -> Self::IntoFuture {
private::ServeFuture {
inner: async move {
while let Some(stream_request) = self.stream_requests.next().await {
let data_stream = match stream_request.request() {
IncomingStreamRequest::Begin(_) => {
match stream_request.accept(Connected::new_empty()).await {
Ok(data_stream) => data_stream,
Err(error) => {
error!("failed to accept incoming stream: {error}");
continue;
}
}
}
_ => {
// we only accept BEGIN streams
continue;
}
};
poll_fn(|cx| self.make_service.poll_ready(cx))
.await
.unwrap_or_else(|err| match err {});
let incoming_stream = IncomingStream {
data_stream: &data_stream,
};
let tower_service = self
.make_service
.call(incoming_stream)
.await
.unwrap_or_else(|err| match err {});
let transformed_service = MapRequestBodyService {
inner: tower_service,
};
let hyper_service = TowerToHyperService::new(transformed_service);
tokio::spawn(async move {
match Builder::new(TokioExecutor::new())
// upgrades needed for websockets
.serve_connection_with_upgrades(
TokioIo::new(data_stream),
hyper_service,
)
.await
{
Ok(()) => {}
Err(_err) => {
// This error only appears when the client
// doesn't send a request and
// terminate the connection.
//
// If client sends one request then terminate
// connection whenever, it doesn't
// appear.
}
}
});
}
}
.boxed(),
}
}
}
mod private {
use super::*;
pub struct ServeFuture {
pub inner: BoxFuture<'static, ()>,
}
impl Future for ServeFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.inner.poll_unpin(cx)
}
}
}
#[derive(Clone)]
struct MapRequestBodyService<S> {
inner: S,
}
/// A Tower service that transforms the body of incoming requests from
/// `Incoming` to `Body` and delegates the transformed request to the inner
/// service.
impl<S> Service<Request<Incoming>> for MapRequestBodyService<S>
where
S: Service<Request<Body>>,
{
type Response = S::Response;
type Error = S::Error;
type Future = S::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, req: Request<Incoming>) -> Self::Future {
let req = req.map(Body::new);
self.inner.call(req)
}
}
/// An incoming stream.
///
/// This is a single client connecting over the TOR network to your onion
/// service.
pub struct IncomingStream<'a> {
// in the future we can use this to return information about the circuit used etc.
#[allow(dead_code)]
data_stream: &'a DataStream,
}
impl Service<IncomingStream<'_>> for Router<()> {
type Response = Router;
type Error = Infallible;
type Future = std::future::Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _req: IncomingStream<'_>) -> Self::Future {
std::future::ready(Ok(self.clone()))
}
}