Start tor from test

This commit is contained in:
Philipp Hoenisch 2020-10-20 16:14:10 +11:00
parent 295216a8ee
commit a73f1fcc6f
No known key found for this signature in database
GPG Key ID: E5F8E74C672BC666
2 changed files with 120 additions and 56 deletions

View File

@ -10,17 +10,37 @@ use torut::{
onion::TorSecretKeyV3, onion::TorSecretKeyV3,
}; };
lazy_static! { // lazy_static! {
/// The default TOR socks5 proxy address, `127.0.0.1:9050`. // The default TOR socks5 proxy address, `127.0.0.1:9050`.
pub static ref TOR_PROXY_ADDR: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 9050); // pub static ref TOR_PROXY_ADDR: SocketAddrV4 =
/// The default TOR Controller Protocol address, `127.0.0.1:9051`. // SocketAddrV4::new(Ipv4Addr::LOCALHOST, 9050); The default TOR Controller
pub static ref TOR_CP_ADDR: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 9051)); // Protocol address, `127.0.0.1:9051`. pub static ref TOR_CP_ADDR: SocketAddr =
// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 9051)); }
type Handler = fn(AsyncEvent<'_>) -> Box<dyn Future<Output = Result<(), ConnError>> + Unpin>;
#[allow(missing_debug_implementations)]
pub struct AuthenticatedConnection {
tor_proxy_address: SocketAddrV4,
tor_control_port_address: SocketAddr,
authenticated_connection: Option<AuthenticatedConn<TcpStream, Handler>>,
} }
impl Default for AuthenticatedConnection {
fn default() -> Self {
Self {
tor_proxy_address: SocketAddrV4::new(Ipv4Addr::LOCALHOST, 9050),
tor_control_port_address: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 9051)),
authenticated_connection: None,
}
}
}
impl AuthenticatedConnection {
/// checks if tor is running /// checks if tor is running
async fn tor_running() -> Result<()> { async fn tor_running(&self) -> Result<()> {
// Make sure you are running tor and this is your socks port // Make sure you are running tor and this is your socks port
let proxy = reqwest::Proxy::all(format!("socks5h://{}", *TOR_PROXY_ADDR).as_str()) let proxy = reqwest::Proxy::all(format!("socks5h://{}", self.tor_proxy_address).as_str())
.expect("tor proxy should be there"); .expect("tor proxy should be there");
let client = reqwest::Client::builder() let client = reqwest::Client::builder()
.proxy(proxy) .proxy(proxy)
@ -39,24 +59,29 @@ async fn tor_running() -> Result<()> {
} }
} }
type Handler = fn(AsyncEvent<'_>) -> Box<dyn Future<Output = Result<(), ConnError>> + Unpin>; async fn init_unauthenticated_connection(&self) -> Result<UnauthenticatedConn<TcpStream>> {
#[allow(missing_debug_implementations)]
pub struct AuthenticatedConnection(AuthenticatedConn<TcpStream, Handler>);
impl AuthenticatedConnection {
async fn init_unauthenticated_connection() -> Result<UnauthenticatedConn<TcpStream>> {
// try to connect to local tor service via control port // try to connect to local tor service via control port
let sock = TcpStream::connect(*TOR_CP_ADDR).await?; let sock = TcpStream::connect(self.tor_control_port_address).await?;
let unauthenticated_connection = UnauthenticatedConn::new(sock); let unauthenticated_connection = UnauthenticatedConn::new(sock);
Ok(unauthenticated_connection) Ok(unauthenticated_connection)
} }
/// Create a new authenticated connection to your local Tor service pub fn with_ports(proxy_port: u16, control_port: u16) -> Self {
pub async fn new() -> Result<Self> { Self {
tor_running().await?; tor_proxy_address: SocketAddrV4::new(Ipv4Addr::LOCALHOST, proxy_port),
tor_control_port_address: SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::LOCALHOST,
control_port,
)),
authenticated_connection: None,
}
}
let mut unauthenticated_connection = match Self::init_unauthenticated_connection().await { /// Create a new authenticated connection to your local Tor service
pub async fn connect(self) -> Result<Self> {
self.tor_running().await?;
let mut unauthenticated_connection = match self.init_unauthenticated_connection().await {
Err(_) => bail!("Tor instance not running"), Err(_) => bail!("Tor instance not running"),
Ok(unauthenticated_connection) => unauthenticated_connection, Ok(unauthenticated_connection) => unauthenticated_connection,
}; };
@ -79,13 +104,18 @@ impl AuthenticatedConnection {
} }
let authenticated_connection = unauthenticated_connection.into_authenticated().await; let authenticated_connection = unauthenticated_connection.into_authenticated().await;
Ok(AuthenticatedConnection(authenticated_connection)) Ok(AuthenticatedConnection {
authenticated_connection: Some(authenticated_connection),
..self
})
} }
/// Add an ephemeral tor service on localhost with the provided key /// Add an ephemeral tor service on localhost with the provided key
pub async fn add_service(&mut self, port: u16, tor_key: &TorSecretKeyV3) -> Result<()> { pub async fn add_service(&mut self, port: u16, tor_key: &TorSecretKeyV3) -> Result<()> {
self.0 match self.authenticated_connection {
.add_onion_v3( None => bail!("Not connected to local tor instance"),
Some(ref mut aut) => {
aut.add_onion_v3(
tor_key, tor_key,
false, false,
false, false,
@ -99,6 +129,9 @@ impl AuthenticatedConnection {
) )
.await .await
.map_err(|_| anyhow!("Could not add onion service."))?; .map_err(|_| anyhow!("Could not add onion service."))?;
}
}
Ok(()) Ok(())
} }
} }

View File

@ -5,10 +5,13 @@ mod tor_test {
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use reqwest::StatusCode; use reqwest::StatusCode;
use spectral::prelude::*; use spectral::prelude::*;
use std::convert::Infallible; use std::{convert::Infallible, process::Child};
use tokio::sync::oneshot::Receiver; use tokio::sync::oneshot::Receiver;
use torut::onion::TorSecretKeyV3; use torut::{
use xmr_btc::tor::{AuthenticatedConnection, TOR_PROXY_ADDR}; onion::TorSecretKeyV3,
utils::{run_tor, AutoKillChild},
};
use xmr_btc::tor::AuthenticatedConnection;
async fn hello_world( async fn hello_world(
_req: hyper::Request<hyper::Body>, _req: hyper::Request<hyper::Body>,
@ -32,15 +35,43 @@ mod tor_test {
}); });
} }
fn run_tmp_tor() -> (Child, u16, u16) {
let control_port = 9051;
let proxy_port = 9050;
(
run_tor(
"tor",
&mut [
"--CookieAuthentication",
"1",
"--ControlPort",
control_port.to_string().as_str(),
]
.iter(),
)
.expect("Starting tor filed"),
control_port,
proxy_port,
)
}
#[tokio::test] #[tokio::test]
async fn test_tor_control_port() -> Result<()> { async fn test_tor_control_port() -> Result<()> {
// start tmp tor
let (child, control_port, proxy_port) = run_tmp_tor();
let _child = AutoKillChild::new(child);
// Setup test HTTP Server // Setup test HTTP Server
let (tx, rx) = tokio::sync::oneshot::channel::<()>(); let (tx, rx) = tokio::sync::oneshot::channel::<()>();
let port = 8080; let port = 8080;
start_test_service(port, rx); start_test_service(port, rx);
// Connect to local Tor service // Connect to local Tor service
let mut authenticated_connection = AuthenticatedConnection::new().await?; let mut authenticated_connection =
AuthenticatedConnection::with_ports(proxy_port, control_port)
.connect()
.await?;
// Expose an onion service that re-directs to the echo server. // Expose an onion service that re-directs to the echo server.
let tor_secret_key_v3 = TorSecretKeyV3::generate(); let tor_secret_key_v3 = TorSecretKeyV3::generate();
@ -50,7 +81,7 @@ mod tor_test {
// Test if Tor service forwards to HTTP Server // Test if Tor service forwards to HTTP Server
let proxy = reqwest::Proxy::all(format!("socks5h://{}", *TOR_PROXY_ADDR).as_str()) let proxy = reqwest::Proxy::all(format!("socks5h://127.0.0.1:{}", proxy_port).as_str())
.expect("tor proxy should be there"); .expect("tor proxy should be there");
let client = reqwest::Client::builder().proxy(proxy).build().unwrap(); let client = reqwest::Client::builder().proxy(proxy).build().unwrap();
let onion_address = tor_secret_key_v3.public().get_onion_address().to_string(); let onion_address = tor_secret_key_v3.public().get_onion_address().to_string();