[tor-dev] OnionShare bug that's possibly caused by an upstream v3 onion bug
Micah Lee
micah at micahflee.com
Sun Nov 25 05:30:16 UTC 2018
I've been working on a major OnionShare release that, among other
things, will use v3 onion services by default. But it appears that
either something in stem or in Tor deals with v3 onions differently than
v2 onions, and causes a critical bug in OnionShare. It took a lot of
work to track down exactly how to reproduce this bug, and I haven't
opened an upstream issue for either stem or tor because I feel like I
don't understand it enough yet.
Here is the OnionShare issue [1]. Does anyone know if this is an issue
with stem or tor, and how to go about mitigating it? Here's some
background:
When you share files with OnionShare it starts a local web server and
then makes it an ephemeral onion service. Someone else loads this onion
service in Tor Browser and downloads your files. If the setting "Stop
sharing after first download" is checked (this is the default behavior),
then as soon as the download completes, OnionShare stops the onion
service and web server.
If I share a 1mb file and a Tor Browser client makes an HTTP request to
download it, OnionShare will respond with a 1mb HTTP response. As soon
as it's done sending the 1mb, OnionShare stops the server and alerts the
user that transfer is complete -- however, it's not actually complete
yet. If you look at the client in Tor Browser, it's still downloading.
It depends on the Tor circuit, but it might be only ~32% done, and you
have to wait a few seconds for it to finish. This is because when the
final byte of the 1mb file leaves the OnionShare web server, it takes a
few seconds for that final byte to make it through the onion circuit and
into Tor Browser download.
This works fine with v2 onion services.
But with v3 onion services, as soon as the OnionShare web server
finishes sending the full HTTP response, the torified HTTP client stops
downloading. I made a small python script, onion-bug.py, that reproduces
the issue that you can test [2].
This script connects to the default Tor control port for Tor Browser, so
open Tor Browser in the background. It then start an HTTP server and
creates an onion service, and if you make a GET request to the server it
responds with 2mb of "A" characters, and then immediately stops the web
server and onion service. You have to pass in either "v2" or "v3",
depending on which type of onion service to make. Like OnionShare, this
script uses stem, and specifically the
Controller.create_ephemeral_hidden_service method [3].
I just ran "./onion-bug.py v2" in one terminal and waited for it to
start:
```
$ ./onion-bug.py v2
http service: http://127.0.0.1:8080/
starting onion service with: key_type='NEW', key_content='RSA1024'
http://d7vomh45i7ryhhfw.onion/
```
Then in a second terminal, I made the GET request:
```
$ torify curl http://d7vomh45i7ryhhfw.onion/ > out2
% Total % Received % Xferd Average Speed Time Time Time
Current
Dload Upload Total Spent Left
Speed
100 1024k 0 1024k 0 0 125k 0 --:--:-- 0:00:08 --:--:--
245k
```
The script in the first terminal finished and quit (while curl on the
second term finished the download for a few more seconds):
```
127.0.0.1 - - [24/Nov/2018 21:12:52] "GET / HTTP/1.1" 200 -
shutting down http server
```
The file, out1, is exactly 1mb.
Now I tried doing the same, but with a v3 onion service:
```
$ ./onion-bug.py v3
http service: http://127.0.0.1:8080/
starting onion service with: key_type='NEW', key_content='ED25519-V3'
http://htrzngqgb7ogyifsvah6qz7t6spe3rr7bikdws7d3rigkpwy5kuyrlqd.onion/
127.0.0.1 - - [24/Nov/2018 21:14:22] "GET / HTTP/1.1" 200 -
shutting down http server
```
And in the other terminal:
```
$ torify curl
http://htrzngqgb7ogyifsvah6qz7t6spe3rr7bikdws7d3rigkpwy5kuyrlqd.onion/ >
out2
% Total % Received % Xferd Average Speed Time Time Time
Current
Dload Upload Total Spent Left
Speed
100 29830 0 29830 0 0 3399 0 --:--:-- 0:00:08 --:--:--
3399
```
It only downloaded 29830 bytes before the download connection stopped,
so out2 is only 30kb. I just tried it again, and this time only got 12kb
downloaded. And I tried it again, and got 41kb downloaded. It appears to
depend on the speed of the Tor circuit.
The download only stops when the v3 onion service is shut down -- if you
uncomment out the time.sleep(5) before calling
remove_ephemeral_hidden_service at the end of the script, you'll be able
to download the full 1mb using the v3 onion server.
I'm pretty stumped on how to fix this and I'd appreciate any help.
Until it's fixed, we'll either have to not include support for v3 onion
services in OnionShare in the next major release (version 2.0), or
include support but with the "Stop sharing after first download" only
available for v2 onion services -- so probably we'd default to using v2
onion services, and users could optionally use v3 if they don't need the
autostop feature. Of course, I'd much prefer to find a way to solve this
and release with v3 onion services by default.
[1] https://github.com/micahflee/onionshare/issues/812
[2] https://gist.github.com/micahflee/bade960e96d35007bc5c182a0ca61b56
[3]
https://stem.torproject.org/api/control.html#stem.control.Controller.create_ephemeral_hidden_service
More information about the tor-dev
mailing list