Onionprobe implementation using Arti
Description
For the long term, another Onionprobe implementation should be written using Arti's RPC:
- Both old Python/Stem and new Arti implementations can share this repository, as well as existing Prometheus/Grafana and other configurations.
- Both implementations could be supported while both C Tor and Arti implementations are supported, as a Stem-to-Arti transition phase.
- A thin Python wrapper could be used to invoke each implementation depending on command line or configuration file parameter.
Background
Onionprobe's currently relies on Stem, which not much maintained these days, so this dependency needs to be replaced at some point:
Initially, these options were considered:
- Use a fork, or keep using the official branch if it gets maintained again:
- Move to Arti as the new Tor
implementation. This requires a major rewrite on Onionprobe. Options:
- a. Create an Onionprobe implemntation using Arti/Rust (either using Arti's API directly or through Arti's RPC).
- b. Refactor Onionprobe to be implementation-agnostic, supporting both the current logic with Stem and another library using the Python bindings for Arti.
While option 1 means giving an additional, but still short, lifespan to the current Python implementation, it does not account for the C Tor deprecation in the long term.
Therefore, option 2 seems to be the best choice, as it would last longer.
Architecture
As the current Python implementation is too convoluted with Stem, another implementation written from scratch in pure Rust would be the best approach.
One possible pathway is to create a thin wrapper in Python, that only opens the config file (or gets a command line parameter) to check which backend to use, and then calls the appropriate implementation:
- If it's the Python/Stem implementation, it can proceed importing the
needed modules and calling
run_from_cmdline()
directly, as usual. - If it's the Arti implementation, it can proceed accordingly, either spawning a subprocess (if the implementation is written in Rust), or importing its Python modules.
If both exports the same metrics in the same Prometheus format, then the existing dashboard and alerts configuration could be shared by the two implementations.
Implementation
Some options for the Arti implementation:
- Use Arti bindings for Python:
- But it may not be stable yet.
- Use Arti's API straight away:
- But that can be complicated, given it's async behavior.
- Use Rust and Arti's RPC:
- It's now stable since Arti 1.4.2.
- Might be a good opportunity to test and help improving it.
Paraphrasing cve's comment:
-
The RPC approach has the advantage that it is in theory language agnostic and would allow to continue using Python for Onionprobe; on the other side, the RPC interface is – although stable since yesterday – very feature limited, its already sufficient for connecting to hidden services. An advantage would be, that we would be one of the first applications experimenting with the API.
-
The API approach would force a rewrite in Rust. This is not bad per-se but its still something we have to take into account. On the other side, this approach is probably more mature.
Planning
In terms of planning,
-
A feature matrix table could be built (similar to this one), tracking which features are supported by each backend.
-
At some point, the Python implementation could be marked as feature-complete, and users be recommended to migrate to the Rust version once it has the needed features.
Tasks
-
Discuss/decide/improve the plan outlined above. -
Add more tasks to this list :)