Add support for stealth onion services in CLI version

This commit is contained in:
Micah Lee 2016-12-22 16:56:39 -08:00
parent fd41eac48d
commit eff0d3729a
No known key found for this signature in database
GPG Key ID: 403C2657CD994F73
3 changed files with 62 additions and 11 deletions

View File

@ -33,6 +33,14 @@ class NoTor(Exception):
"""
pass
class TorTooOld(Exception):
"""
This exception is raised if onionshare needs to use a feature of Tor or stem
(like stealth ephemeral onion services) but the version you have installed
is too old.
"""
pass
class Onion(object):
"""
Onion is an abstraction layer for connecting to the Tor control port and
@ -48,8 +56,9 @@ class Onion(object):
onion services are supported. If not, it falls back to modifying the
Tor configuration.
"""
def __init__(self, transparent_torification=False):
def __init__(self, transparent_torification=False, stealth=False):
self.transparent_torification = transparent_torification
self.stealth = stealth
# files and dirs to delete on shutdown
self.cleanup_filenames = []
@ -89,17 +98,42 @@ class Onion(object):
list_ephemeral_hidden_services = getattr(self.c, "list_ephemeral_hidden_services", None)
self.supports_ephemeral = callable(list_ephemeral_hidden_services) and tor_version >= '0.2.7.1'
# do the versions of stem and tor that I'm using support stealth onion services?
try:
res = self.c.create_ephemeral_hidden_service({1:1}, basic_auth={'onionshare':None}, await_publication=False)
tmp_service_id = res.content()[0][2].split('=')[1]
self.c.remove_ephemeral_hidden_service(tmp_service_id)
self.supports_stealth = True
except TypeError:
# ephemeral stealth onion services are not supported
self.supports_stealth = False
def start(self, port):
"""
Start a onion service on port 80, pointing to the given port, and
return the onion hostname.
"""
print(strings._("connecting_ctrlport").format(int(port)))
self.auth_string = None
if self.stealth and not self.supports_stealth:
raise TorTooOld(strings._('error_stealth_not_supported'))
print(strings._("config_onion_service").format(int(port)))
if self.supports_ephemeral:
print(strings._('using_ephemeral'))
res = self.c.create_ephemeral_hidden_service({ 80: port }, await_publication = True)
if self.stealth:
basic_auth = {'onionshare':None}
else:
basic_auth = None
res = self.c.create_ephemeral_hidden_service({ 80: port }, await_publication=True, basic_auth=basic_auth)
self.service_id = res.content()[0][2].split('=')[1]
onion_host = self.service_id + '.onion'
if self.stealth:
auth_cookie = res.content()[2][2].split('=')[1].split(':')[1]
self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie)
return onion_host
else:

View File

@ -27,7 +27,7 @@ class OnionShare(object):
OnionShare is the main application class. Pass in options and run
start_onion_service and it will do the magic.
"""
def __init__(self, debug=False, local_only=False, stay_open=False, transparent_torification=False):
def __init__(self, debug=False, local_only=False, stay_open=False, transparent_torification=False, stealth=False):
self.port = None
self.onion = None
self.hidserv_dir = None
@ -49,6 +49,9 @@ class OnionShare(object):
# traffic automatically goes through Tor
self.transparent_torification = transparent_torification
# use stealth onion service
self.stealth = stealth
def choose_port(self):
"""
Pick an un-used port in the range 17600-17650 to bind to.
@ -76,10 +79,13 @@ class OnionShare(object):
return
if not self.onion:
self.onion = onion.Onion(self.transparent_torification)
self.onion = onion.Onion(self.transparent_torification, self.stealth)
self.onion_host = self.onion.start(self.port)
if self.stealth:
self.auth_string = self.onion.auth_string
def cleanup(self):
"""
Shut everything down and clean up temporary files, etc.
@ -115,6 +121,7 @@ def main(cwd=None):
parser.add_argument('--local-only', action='store_true', dest='local_only', help=strings._("help_local_only"))
parser.add_argument('--stay-open', action='store_true', dest='stay_open', help=strings._("help_stay_open"))
parser.add_argument('--transparent', action='store_true', dest='transparent_torification', help=strings._("help_transparent_torification"))
parser.add_argument('--stealth', action='store_true', dest='stealth', help=strings._("help_stealth"))
parser.add_argument('--debug', action='store_true', dest='debug', help=strings._("help_debug"))
parser.add_argument('filename', metavar='filename', nargs='+', help=strings._('help_filename'))
args = parser.parse_args()
@ -127,6 +134,7 @@ def main(cwd=None):
debug = bool(args.debug)
stay_open = bool(args.stay_open)
transparent_torification = bool(args.transparent_torification)
stealth = bool(args.stealth)
# validation
valid = True
@ -139,11 +147,13 @@ def main(cwd=None):
# start the onionshare app
try:
app = OnionShare(debug, local_only, stay_open, transparent_torification)
app = OnionShare(debug, local_only, stay_open, transparent_torification, stealth)
app.choose_port()
app.start_onion_service()
except onion.NoTor as e:
sys.exit(e.args[0])
except onion.TorTooOld as e:
sys.exit(e.args[0])
# prepare files to share
print(strings._("preparing_files"))
@ -171,8 +181,13 @@ def main(cwd=None):
# Wait for web.generate_slug() to finish running
time.sleep(0.2)
print(strings._("give_this_url"))
print('http://{0:s}/{1:s}'.format(app.onion_host, web.slug))
if(stealth):
print(strings._("give_this_url_stealth"))
print('http://{0:s}/{1:s}'.format(app.onion_host, web.slug))
print(app.auth_string)
else:
print(strings._("give_this_url"))
print('http://{0:s}/{1:s}'.format(app.onion_host, web.slug))
print('')
print(strings._("ctrlc_to_stop"))

View File

@ -1,5 +1,5 @@
{
"connecting_ctrlport": "Connecting to Tor control port to set up onion service on port {0:d}.",
"config_onion_service": "Configuring onion service on port {0:d}.",
"cant_connect_ctrlport": "Can't connect to Tor control port on port {0:s}. OnionShare requires Tor Browser to be running in the background to work. If you don't have it you can get it from https://www.torproject.org/.",
"cant_connect_socksport": "Can't connect to Tor SOCKS5 server on port {0:s}. OnionShare requires Tor Browser to be running in the background to work. If you don't have it you can get it from https://www.torproject.org/.",
"ctrlport_missing_password": "Connected to Tor control port on port {0:s}, but you require a password. You must have the TOR_AUTHENTICATION_PASSWORD environment variable set. Or just open Tor Browser in the background.",
@ -10,6 +10,7 @@
"wait_for_hs_nope": "Not ready yet.",
"wait_for_hs_yup": "Ready!",
"give_this_url": "Give this URL to the person you're sending the file to:",
"give_this_url_stealth": "Give this URL and HidServAuth line to the person you're sending the file to:",
"ctrlc_to_stop": "Press Ctrl-C to stop server",
"not_a_file": "{0:s} is not a file.",
"download_page_loaded": "Download page loaded",
@ -19,10 +20,10 @@
"large_filesize": "Warning: Sending large files could take hours",
"error_tails_invalid_port": "Invalid value, port must be an integer",
"error_tails_unknown_root": "Unknown error with Tails root process",
"help_tails_port": "Tails only: port for opening firewall, starting onion service",
"help_local_only": "Do not attempt to use tor: for development only",
"help_stay_open": "Keep onion service running after download has finished",
"help_transparent_torification": "My system is transparently torified",
"help_stealth": "Create stealth onion service (advanced)",
"help_debug": "Log errors to disk",
"help_filename": "List of files or folders to share",
"gui_drag_and_drop": "Drag and drop\nfiles here",
@ -52,5 +53,6 @@
"gui_quit_warning_quit": "Quit",
"gui_quit_warning_dont_quit": "Don't Quit",
"error_rate_limit": "An attacker might be trying to guess your URL. To prevent this, OnionShare has automatically stopped the server. To share the files you must start it again and share the new URL.",
"zip_progress_bar_format": "Crunching files: %p%"
"zip_progress_bar_format": "Crunching files: %p%",
"error_stealth_not_supported": "Your versions of tor or stem are too old. You need to upgrade them to create stealth onion services."
}