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,53 +10,78 @@ 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)); }
/// checks if tor is running
async fn tor_running() -> Result<()> {
// Make sure you are running tor and this is your socks port
let proxy = reqwest::Proxy::all(format!("socks5h://{}", *TOR_PROXY_ADDR).as_str())
.expect("tor proxy should be there");
let client = reqwest::Client::builder()
.proxy(proxy)
.build()
.expect("should be able to build reqwest client");
let res = client.get("https://check.torproject.org").send().await?;
let text = res.text().await?;
let is_tor = text.contains("Congratulations. This browser is configured to use Tor.");
if is_tor {
Ok(())
} else {
bail!("Tor is currently not running")
}
}
type Handler = fn(AsyncEvent<'_>) -> Box<dyn Future<Output = Result<(), ConnError>> + Unpin>; type Handler = fn(AsyncEvent<'_>) -> Box<dyn Future<Output = Result<(), ConnError>> + Unpin>;
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub struct AuthenticatedConnection(AuthenticatedConn<TcpStream, Handler>); 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 { impl AuthenticatedConnection {
async fn init_unauthenticated_connection() -> Result<UnauthenticatedConn<TcpStream>> { /// checks if tor is running
async fn tor_running(&self) -> Result<()> {
// Make sure you are running tor and this is your socks port
let proxy = reqwest::Proxy::all(format!("socks5h://{}", self.tor_proxy_address).as_str())
.expect("tor proxy should be there");
let client = reqwest::Client::builder()
.proxy(proxy)
.build()
.expect("should be able to build reqwest client");
let res = client.get("https://check.torproject.org").send().await?;
let text = res.text().await?;
let is_tor = text.contains("Congratulations. This browser is configured to use Tor.");
if is_tor {
Ok(())
} else {
bail!("Tor is currently not running")
}
}
async fn init_unauthenticated_connection(&self) -> 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,26 +104,34 @@ 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"),
tor_key, Some(ref mut aut) => {
false, aut.add_onion_v3(
false, tor_key,
false, false,
None, false,
&mut [( false,
port, None,
SocketAddr::new(IpAddr::from(Ipv4Addr::new(127, 0, 0, 1)), port), &mut [(
)] port,
.iter(), SocketAddr::new(IpAddr::from(Ipv4Addr::new(127, 0, 0, 1)), port),
) )]
.await .iter(),
.map_err(|_| anyhow!("Could not add onion service."))?; )
.await
.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();