mirror of
https://github.com/logos-storage/tor-experiments.git
synced 2026-01-02 13:53:12 +00:00
add hidden-service tests
This commit is contained in:
parent
f8d9b989cf
commit
981304c3a5
10
Cargo.toml
10
Cargo.toml
@ -13,4 +13,12 @@ arti-ureq = "0.35"
|
||||
tor-rtcompat = "0.35"
|
||||
tor-circmgr = "0.35"
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util"] }
|
||||
futures = "0.3.14"
|
||||
futures = "0.3.14"
|
||||
tor-hsservice = "0.35"
|
||||
tor-proto = "0.35"
|
||||
axum = { version = "0.8.1" }
|
||||
tor-cell = "0.35"
|
||||
safelog = { version = "0.6.0" }
|
||||
hyper-util = { version = "0.1.1", features = ["tokio"] }
|
||||
hyper = { version = "1", features = ["http1", "server"] }
|
||||
tower = { version = "0.5.1", features = ["util", "tracing"] }
|
||||
84
src/hidden_service.rs
Normal file
84
src/hidden_service.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use axum::Router;
|
||||
use axum::routing::get;
|
||||
use arti_client::TorClient;
|
||||
use arti_ureq::ureq::http::Request;
|
||||
use futures::StreamExt;
|
||||
use hyper::body::Incoming;
|
||||
use hyper_util::rt::{TokioExecutor, TokioIo};
|
||||
use hyper_util::server;
|
||||
use tor_hsservice::config::OnionServiceConfigBuilder;
|
||||
use tor_proto::client::stream::IncomingStreamRequest;
|
||||
use safelog::{DisplayRedacted as _, sensitive};
|
||||
use tor_cell::relaycell::msg::Connected;
|
||||
use tor_hsservice::StreamRequest;
|
||||
use tower::Service;
|
||||
|
||||
/// returns the axum router for the hidden service
|
||||
/// The router will serve the given string as a response to any GET request on the root path
|
||||
pub fn get_service_router(msg: String) -> Router {
|
||||
let router = Router::new().route("/", get(|| async { msg }));
|
||||
router
|
||||
}
|
||||
|
||||
/// launch the hidden service following the arti instructions.
|
||||
/// The function uses both hyper and axum to serve.
|
||||
/// this function launches the hidden service using the given client and router
|
||||
/// then waits for requests.
|
||||
pub async fn launch_hidden_service(tor_client: TorClient<tor_rtcompat::PreferredRuntime>, router: Router){
|
||||
let svc_cfg = OnionServiceConfigBuilder::default()
|
||||
.nickname("hello-world-8273649267405".parse().unwrap())
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let (service, request_stream) = tor_client.launch_onion_service(svc_cfg).unwrap();
|
||||
println!("service is running on: {}", service.onion_address().unwrap().display_unredacted());
|
||||
|
||||
eprintln!("waiting for service to become fully reachable");
|
||||
while let Some(status) = service.status_events().next().await {
|
||||
if status.state().is_fully_reachable() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let stream_requests = tor_hsservice::handle_rend_requests(request_stream);
|
||||
tokio::pin!(stream_requests);
|
||||
eprintln!("ready to serve connections");
|
||||
|
||||
while let Some(stream_request) = stream_requests.next().await {
|
||||
let router = router.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let request = stream_request.request().clone();
|
||||
if let Err(err) = handle_requests(stream_request, router).await {
|
||||
eprintln!("error serving connection {:?}: {}", sensitive(request), err);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
drop(service);
|
||||
eprintln!("onion service exited cleanly");
|
||||
}
|
||||
|
||||
/// this function serves the incoming requests to the hidden service using the given stream and router
|
||||
async fn handle_requests(stream_request: StreamRequest, router: Router) -> anyhow::Result<()> {
|
||||
match stream_request.request() {
|
||||
IncomingStreamRequest::Begin(begin) if begin.port() == 80 => {
|
||||
let onion_service_stream = stream_request.accept(Connected::new_empty()).await?;
|
||||
let io = TokioIo::new(onion_service_stream);
|
||||
|
||||
let hyper_service = hyper::service::service_fn(move |request: Request<Incoming>| {
|
||||
router.clone().call(request)
|
||||
});
|
||||
|
||||
server::conn::auto::Builder::new(TokioExecutor::new())
|
||||
.serve_connection(io, hyper_service)
|
||||
.await
|
||||
.map_err(|x| anyhow::anyhow!(x))?;
|
||||
}
|
||||
_ => {
|
||||
stream_request.shutdown_circuit()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
pub mod ureq_builder;
|
||||
pub mod tests;
|
||||
pub mod tor_client_builder;
|
||||
pub mod tor_client_builder;
|
||||
pub mod hidden_service;
|
||||
@ -1,5 +1,5 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
pub mod tests {
|
||||
use anyhow::Result;
|
||||
use arti_client::TorClient;
|
||||
use crate::ureq_builder::*;
|
||||
@ -12,7 +12,7 @@ mod tests {
|
||||
const TEST_URL_PATH_HTTP_PLAIN: &str = "/api/ip";
|
||||
// We will use the following onion address with the tor client.
|
||||
const TEST_ONION: &str = "2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion";
|
||||
const TEST_ONION_PATH: &str = "/";
|
||||
pub const TEST_ONION_PATH: &str = "/";
|
||||
/// Builds all components
|
||||
fn build_ureq_agent() -> Result<Agent> {
|
||||
let tls = choose_tls_provider();
|
||||
|
||||
@ -1 +1,2 @@
|
||||
pub mod get_request_tests;
|
||||
pub mod get_request_tests;
|
||||
pub mod test_hidden_service;
|
||||
44
src/tests/test_hidden_service.rs
Normal file
44
src/tests/test_hidden_service.rs
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::get_request_tests::tests::TEST_ONION_PATH;
|
||||
use anyhow::Result;
|
||||
use arti_client::TorClient;
|
||||
use crate::hidden_service::{get_service_router, launch_hidden_service};
|
||||
use crate::tor_client_builder::{ fetch_with_client, make_tor_client_config};
|
||||
|
||||
// we will use this as the output of the hidden service
|
||||
const HELLO_WORLD: &str = "Hello, world!";
|
||||
|
||||
/// Test: launch a `hello_world` hidden service
|
||||
/// This test may take a little while to run
|
||||
/// Warning: this will not terminate.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_launch_hidden_service() -> Result<()> {
|
||||
let config = make_tor_client_config();
|
||||
|
||||
let tor_client = TorClient::create_bootstrapped(config).await.unwrap();
|
||||
|
||||
let router = get_service_router(HELLO_WORLD.to_string());
|
||||
launch_hidden_service(tor_client, router).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test: send get request to onion address over Tor using the tor client.
|
||||
/// again this is http and no tls
|
||||
/// warning: this will print out an entire html page
|
||||
async fn fetches_onion_url_over_tor_client(onion_url: &str) -> Result<()> {
|
||||
let config = make_tor_client_config();
|
||||
|
||||
let tor_client = TorClient::builder()
|
||||
.config(config)
|
||||
.create_unbootstrapped()?;
|
||||
|
||||
let body = fetch_with_client(tor_client, onion_url, TEST_ONION_PATH).await?;
|
||||
//sanity check:
|
||||
assert!(!body.trim().is_empty(), "empty body from {}", onion_url);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,10 +5,10 @@ use arti_ureq::ureq::tls::RootCerts;
|
||||
/// Build a Connector from the Tor client and chosen TLS provider.
|
||||
/// This is a ureq connector, and here we are giving it out already created tor client + tls
|
||||
pub fn make_connector(
|
||||
tor_client: arti_client::TorClient<arti_ureq::tor_rtcompat::PreferredRuntime>,
|
||||
tor_client: arti_client::TorClient<tor_rtcompat::PreferredRuntime>,
|
||||
tls_provider: ureq::tls::TlsProvider,
|
||||
) -> Result<arti_ureq::Connector<arti_ureq::tor_rtcompat::PreferredRuntime>> {
|
||||
let builder = arti_ureq::Connector::<arti_ureq::tor_rtcompat::PreferredRuntime>::builder()
|
||||
) -> Result<arti_ureq::Connector<tor_rtcompat::PreferredRuntime>> {
|
||||
let builder = arti_ureq::Connector::<tor_rtcompat::PreferredRuntime>::builder()
|
||||
.context("Failed to create ConnectorBuilder")?
|
||||
.tor_client(tor_client)
|
||||
.tls_provider(tls_provider);
|
||||
@ -18,7 +18,7 @@ pub fn make_connector(
|
||||
|
||||
/// Build a `ureq::Agent`
|
||||
pub fn make_ureq_agent(
|
||||
connector: arti_ureq::Connector<arti_ureq::tor_rtcompat::PreferredRuntime>,
|
||||
connector: arti_ureq::Connector<tor_rtcompat::PreferredRuntime>,
|
||||
tls_provider: ureq::tls::TlsProvider,
|
||||
) -> Result<ureq::Agent> {
|
||||
// Build ureq TLS config
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user