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 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): class Onion(object):
""" """
Onion is an abstraction layer for connecting to the Tor control port and 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 onion services are supported. If not, it falls back to modifying the
Tor configuration. Tor configuration.
""" """
def __init__(self, transparent_torification=False): def __init__(self, transparent_torification=False, stealth=False):
self.transparent_torification = transparent_torification self.transparent_torification = transparent_torification
self.stealth = stealth
# files and dirs to delete on shutdown # files and dirs to delete on shutdown
self.cleanup_filenames = [] self.cleanup_filenames = []
@ -89,17 +98,42 @@ class Onion(object):
list_ephemeral_hidden_services = getattr(self.c, "list_ephemeral_hidden_services", None) 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' 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): def start(self, port):
""" """
Start a onion service on port 80, pointing to the given port, and Start a onion service on port 80, pointing to the given port, and
return the onion hostname. 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: if self.supports_ephemeral:
print(strings._('using_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] self.service_id = res.content()[0][2].split('=')[1]
onion_host = self.service_id + '.onion' 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 return onion_host
else: else:

View file

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

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_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/.", "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.", "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_nope": "Not ready yet.",
"wait_for_hs_yup": "Ready!", "wait_for_hs_yup": "Ready!",
"give_this_url": "Give this URL to the person you're sending the file to:", "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", "ctrlc_to_stop": "Press Ctrl-C to stop server",
"not_a_file": "{0:s} is not a file.", "not_a_file": "{0:s} is not a file.",
"download_page_loaded": "Download page loaded", "download_page_loaded": "Download page loaded",
@ -19,10 +20,10 @@
"large_filesize": "Warning: Sending large files could take hours", "large_filesize": "Warning: Sending large files could take hours",
"error_tails_invalid_port": "Invalid value, port must be an integer", "error_tails_invalid_port": "Invalid value, port must be an integer",
"error_tails_unknown_root": "Unknown error with Tails root process", "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_local_only": "Do not attempt to use tor: for development only",
"help_stay_open": "Keep onion service running after download has finished", "help_stay_open": "Keep onion service running after download has finished",
"help_transparent_torification": "My system is transparently torified", "help_transparent_torification": "My system is transparently torified",
"help_stealth": "Create stealth onion service (advanced)",
"help_debug": "Log errors to disk", "help_debug": "Log errors to disk",
"help_filename": "List of files or folders to share", "help_filename": "List of files or folders to share",
"gui_drag_and_drop": "Drag and drop\nfiles here", "gui_drag_and_drop": "Drag and drop\nfiles here",
@ -52,5 +53,6 @@
"gui_quit_warning_quit": "Quit", "gui_quit_warning_quit": "Quit",
"gui_quit_warning_dont_quit": "Don't 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.", "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."
} }