Skip to content

Commit eb261a0

Browse files
Detect Whonix and Tails, connect to their Tors specially
1 parent 06b6da5 commit eb261a0

File tree

3 files changed

+52
-3
lines changed

3 files changed

+52
-3
lines changed

swap-tor/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ anyhow = { workspace = true }
1010
arti-client = { workspace = true, features = ["static-sqlite", "tokio", "rustls", "onion-service-service"] }
1111
data-encoding = "2.6"
1212
libp2p = { workspace = true, features = ["tcp", "dns", "tokio"] }
13+
once_cell = { workspace = true }
1314

1415
# Tokio
1516
tokio = { workspace = true, features = ["net"] }

swap-tor/src/lib.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use arti_client::TorClient;
22
use libp2p::core::multiaddr::Protocol;
33
use libp2p::core::transport::{ListenerId, TransportEvent};
44
use libp2p::{Multiaddr, Transport, TransportError};
5+
use std::fs;
56
use std::future::Future;
67
use std::net::SocketAddr;
78
use std::pin::Pin;
@@ -160,3 +161,46 @@ impl std::fmt::Debug for TorBackend {
160161
})
161162
}
162163
}
164+
165+
#[derive(Copy, Clone, Debug)]
166+
pub enum SpecialTorEnvironment {
167+
/// Torsocksed userland, Tor control and SOCKS5 in `$TOR_...`, well-known SOCKS5 at `127.0.0.1:9050`
168+
///
169+
/// The `$TOR_...` configuration uses unix-domain sockets which we'd have to wrap ourselves
170+
///
171+
/// We can't support a hypothetical `TorsocksTransport` that'd substitute
172+
/// /onion3/cebulka7uxchnbpvmqapg5pfos4ngaxglsktzvha7a5rigndghvadeyd:13
173+
/// with
174+
/// /dns/cebulka7uxchnbpvmqapg5pfos4ngaxglsktzvha7a5rigndghvadeyd.onion/tcp/13
175+
/// then forward to TcpTransport,
176+
/// because [hickory-resolver refuses to resolve `.onion` addresses](https://github.com/hickory-dns/hickory-dns/issues/3331).
177+
Whonix,
178+
/// Well-known SOCKS5 at `127.0.0.1:9050`, cf. `/usr/local/bin/curl`
179+
///
180+
/// Userland pretends it's torsocksed but dialling actually doesn't work at all; *all* network traffic must go through SOCKS5.
181+
Tails,
182+
}
183+
184+
pub static TOR_ENVIRONMENT: once_cell::sync::Lazy<Option<SpecialTorEnvironment>> =
185+
once_cell::sync::Lazy::new(|| {
186+
if fs::exists("/usr/share/whonix/marker").unwrap_or(false) {
187+
Some(SpecialTorEnvironment::Whonix)
188+
} else if fs::read_to_string("/etc/os-release")
189+
.unwrap_or(String::new())
190+
.contains(r#"ID="tails""#)
191+
{
192+
Some(SpecialTorEnvironment::Tails)
193+
} else {
194+
None
195+
}
196+
});
197+
198+
impl SpecialTorEnvironment {
199+
pub fn backend(self) -> TorBackend {
200+
match self {
201+
Self::Whonix | Self::Tails => TorBackend::Socks(SocksServerAddress(
202+
(std::net::Ipv4Addr::LOCALHOST, 9050).into(),
203+
)),
204+
}
205+
}
206+
}

swap/src/common/tor.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ use tor_rtcompat::tokio::TokioRustlsRuntime;
1313

1414
/// Creates an unbootstrapped Tor client or connects to well-known Tor daemon, depending on configuration.
1515
///
16-
/// 1. if the caller requests (user enables) `tor`: prepare an Arti client
17-
/// 2. `None`
16+
/// 1. if on a system with special Tor requirements (Whonix, Tails): call the daemon appropriately
17+
/// 2. if the caller requests (user enables) `tor`: prepare an Arti client
18+
/// 3. `None`
1819
pub async fn create_tor_client(data_dir: &Path, tor: bool) -> Result<TorBackend, Error> {
19-
Ok(if tor {
20+
Ok(if let Some(ste) = *TOR_ENVIRONMENT {
21+
tracing::info!("On {ste:?}, not starting Tor");
22+
ste.backend()
23+
} else if tor {
2024
TorBackend::Arti(Arc::new(create_arti_tor_client(data_dir).await?))
2125
} else {
2226
TorBackend::None

0 commit comments

Comments
 (0)