-
Notifications
You must be signed in to change notification settings - Fork 28
feat: Tails+Whonix support #634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
@binarybaron's checklist:
|
fc53eab to
4cf1d18
Compare
| */ | ||
| function MoneroTorSettings() { | ||
| // Hide this setting if it's superseded by the global Tor connection | ||
| if (torForced) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
React hooks must never be called conditionally
You need to move this below the hook calls.
I'm happy to see you take this on!
The adapter should not be relying on libp2p as it will not only be used for libp2p but also for other things in the future (bdk, monero-rpc-pool). It should be more low level and expose an interface similar to Please also make sure to put as little business logic into the frontend as possible. |
673e9dc to
8f06edd
Compare
|
Since last we spoke, I back-propagated this as I think you'd hoped: I replaced the open-coded I also tested in Tails. Tails userland operates in torsocks mode ( ...and actually, whonix also does this. Since we don't have hidden services, we don't really need to talk to the proxy directly anymore either, and can treat whonix like Tails. This would drop basically all SOCKS5 and socket-related code w.l.o.g., so if you're looking to reduce this as far as possible... I also found a privacy leak that bypasses Tor in some configurations. Please see the second commit from the top ("fix(swap/network): remove DNS leak if using Tor"). |
|
Sound good! Let me know once this is ready for review. |
This is not true. It's supposed to be but it doesn't work on Tails (it works on whonix), and, even if you manage to resolve the address (notably
However, since curl would be broken in basically 100% of cases, and vanilla curl won't resolve .onion addresses, curl is actually /usr/local/bin/curl: Thus, the correct way to dial out on Tails is to connect to a SOCKS5 proxy at well-known address 127.0.0.1:9050, and not to use torsocks. On whonix we can use torsocks instead of calling the tor daemon over SOCKS5 directly (which may reduce the TcpOrUnixStream cruft), or we may call over SOCKS5 instead of torsocks (thus dropping torsocks). I'll re-evaluate which combination of features yields the best-reduced patchset. |
vs so -105 vs -93. I will be retaining SOCKS5 for Tails and Torsocks for whonix. |
8f06edd to
3ca802b
Compare
|
yeah, I got to that, and I think all the other places that do network I/O, last night (it may even be part of the pushed WIP); this was mostly to prime future readers for why it Got Bigger again 😬 |
|
Apparently the default resolver rejects |
9d80f95 to
bc2854f
Compare
|
@binarybaron PTAL. https://foreign.nabijaczleweli.xyz/pub/eigenwallet_3.2.0-rc.4_amd64.AppImage for your testing convenience and assorted screenshots below Functionally this ended up being relatively thin (with a lot of deduplication wins), in taht both whonix and Tails end up using just SocksTransport, which only needs to support TCP so we get about without any wrappers, with a lot of fiddly hook injections: on tails Tails we need to cram a SOCKS5 proxy into every(? should be every, wfm and I don't see any non-TLS-related errors, which I assume is why I don't see any |
Awesome! Thank you for your work. I'll review this as soon as I find the time. I'll also have to get a x86 machine to test this. |
|
@Einliterflasche Please also give this a review. |
|
adding {
"app": {
"windows": [
{
"proxyUrl": "socks5://127.0.0.1:9050"to fixed, convenience AppImage updated |
Awesome progress, I'm confident we can merge this fairly soon! Please consider joining our eigenwallet development Matrix room 💛 |
| // Check for updates when component mounts | ||
| check() | ||
| // Check, CheckOptions for updates when component mounts | ||
| check({ proxy }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to avoid the rust (getUpdaterProxy) -> js -> rust (check) roundtrip and do this in rust directly? There may be a way to configure the updater in src-tauri/lib.rs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately no. The TS API is thus:
async function check(options?: CheckOptions): Promise<Update | null> {
convertToRustHeaders(options)
const metadata = await invoke<UpdateMetadata | null>('plugin:updater|check', {
...options
})
return metadata ? new Update(metadata) : null
}And calls
#[tauri::command]
pub(crate) async fn check<R: Runtime>(
webview: Webview<R>,
headers: Option<Vec<(String, String)>>,
timeout: Option<u64>,
proxy: Option<String>,
target: Option<String>,
allow_downgrades: Option<bool>,
) -> Result<Option<Metadata>> {
let mut builder = webview.updater_builder();
if let Some(headers) = headers {
for (k, v) in headers {
builder = builder.header(k, v)?;
}
}
if let Some(timeout) = timeout {
builder = builder.timeout(Duration::from_millis(timeout));
}
if let Some(ref proxy) = proxy {
let url = Url::parse(proxy.as_str())?;
builder = builder.proxy(url);
}so there's no other way to forward the proxy parameter (it doesn't look like it reads the proxy from the global tauri webview config either, and there's no plugin-global proxy config field).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might be able to create a custom Tauri command that replicates the behaviour but I think that's too much effort for now.
|
Can you also run the formatter ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments, mostly nitpicks. I really like the approach and I am impressed how fast you got a hold of the codebase!
@Einliterflasche will give a review too
|
Let me know if you'd be interested in contributing to the project again! We'd love to have you |
…arm.listen_on() normally
asb::network::transport::new() would use DNS(Tor or TCP), which will resolve DNS queries over plaintext first, before calling them over Tor Cf. cli::transport::new() which correctly does Tor or DNS(TCP) Fix the former to do the latter, delegating domain resolution over Tor as well
…a unified TorBackend
…user about listening on TCP/Onion if the environment doesn't support it (TUI questionnaire)
Bypassing Tor on TorBackend::Socks breaks everything, because /all/ traffic needs to go through the proxy (normal connect() is broken on Tails)
6489811 to
4265a5d
Compare
|
All applied. I'm not opposed to completing more bounties or similar. |
We have a ton of compatibility isuses on Linux which have been hard for us to debug. We are also interested in building a TUI as an alternative for the Web based GUI. If you're interested in working on either of this things, let me know :) |
swap-tor/src/lib.rs
Outdated
| type Output = tokio_util::compat::Compat<TcpStream>; | ||
| type Error = tokio_socks::Error; | ||
| type ListenerUpgrade = std::future::Pending<Result<Self::Output, Self::Error>>; | ||
| type Dial = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send + 'static>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be type Dial = impl Future<Output = ...> + Send + 'static;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet:
error[E0658]: `impl Trait` in associated types is unstable
--> swap-tor/src/lib.rs:79:17
|
79 | type Dial = impl Future<Output = Result<Self::Output, Self::Error>> + Send + 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
error: item does not constrain `<Socks5Transport as libp2p::Transport>::Dial::{opaque#0}`
--> swap-tor/src/lib.rs:104:8
|
104 | fn dial_as_listener(
| ^^^^^^^^^^^^^^^^
|
= note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
note: this opaque type is supposed to be constrained
--> swap-tor/src/lib.rs:79:17
|
79 | type Dial = impl Future<Output = Result<Self::Output, Self::Error>> + Send + 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0658`.
error: could not compile `swap-tor` (lib) due to 2 previous errors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it can be type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>; which is already used in libp2p-tor for its type Dial. Applied that.
|
@Einliterflasche Please also test this on your x86 machine |
|
Can confirm this works on the qubesos/whonix 17 workstatio. |



















See commit messages for detail and full comparison logs, but in short:
In principle, we could start a hidden service, but (a) the user needs to manually edit the configuration of both whonix VMs, (b) this still means talking to the Tor daemon with the control protocol, so (c) that means implementing the whole of the control protocol, and (d) the implementations which are currently in the wild do not support unix-domain socket backends (I did implement them in 2025-06 but the uptake has been slow), so (e) the resulting implementation is humongous (#391), so (f) this has been removed on request: #391 (comment)
AFAICT there's two code paths that can start arti and both are pre-empted by this.
For future extensibility, there are two levels of detexion:
may_init_tor()should returnfalseif standard TCP traffic is routed through Tor ‒ this disables starting artiexisting_tor_config()can then returnSome(...)if there's a Tor-capable SOCKS5 proxy to connect to instead of arti (and preferentially to plain TCP)(For other systems (Tails?) the latter will most likely either reduce to
if is_whonix() || is_tails()orelse if is_tails() { Some(SocksServerAddress::Ip(...)) })(Also some cleanups at the front.)
Cf. #391, #453, https://bounties.monero.social/posts/180/0-789m-make-unstoppable-swap-whonix-friendly