def gen_controller(): connect_method = os.environ.get('connectmethod', 'port') if connect_method == 'port': return Controller.from_port(port=os.environ.get('port', 9051)) elif connect_method == 'socket': return Controller.from_socket_file(path=os.environ.get('socket', '/var/run/tor/control')) else: print("env.connectmethod contains an invalid value. Please specify either 'port' or 'socket'.", file=sys.stderr) sys.exit(-1)
def _on_connect(self): try: self._control = Controller.from_port() except SocketError: try: self._control = Controller.from_socket_file() except SocketError: self._status_icon.set_tooltip_text('Failed to initialize stem') return True self._control.add_status_listener(self._on_status) self._status_icon.set_tooltip_text('Stem: Authenticating') GLib.timeout_add_seconds(1, self._on_auth) return False
def handleKey(self, key): isKeystrokeConsumed = True if key in (ord('n'), ord('N')) and torTools.getConn().isNewnymAvailable(): self.sendNewnym() elif key in (ord('r'), ord('R')) and not self._isTorConnected: controller = None allowPortConnection, allowSocketConnection, _ = starter.allowConnectionTypes() if os.path.exists(self._config["startup.interface.socket"]) and allowSocketConnection: try: # TODO: um... what about passwords? controller = Controller.from_socket_file(self._config["startup.interface.socket"]) controller.authenticate() except (IOError, stem.SocketError), exc: controller = None if not allowPortConnection: cli.popups.showMsg("Unable to reconnect (%s)" % exc, 3) elif not allowPortConnection: cli.popups.showMsg("Unable to reconnect (socket '%s' doesn't exist)" % self._config["startup.interface.socket"], 3) if not controller and allowPortConnection: # TODO: This has diverged from starter.py's connection, for instance it # doesn't account for relative cookie paths or multiple authentication # methods. We can't use the starter.py's connection function directly # due to password prompts, but we could certainly make this mess more # manageable. try: ctlAddr, ctlPort = self._config["startup.interface.ipAddress"], self._config["startup.interface.port"] controller = Controller.from_port(ctlAddr, ctlPort) try: controller.authenticate() except stem.connection.MissingPassword: controller.authenticate(authValue) # already got the password above except Exception, exc: controller = None
sys.exit() # By default attempts to connect using the control socket if it exists. This # skips attempting to connect by socket or port if the user has given # arguments for connecting to the other. controller = None allowPortConnection, allowSocketConnection, allowDetachedStart = allowConnectionTypes() socketPath = param["startup.interface.socket"] if os.path.exists(socketPath) and allowSocketConnection: try: # TODO: um... what about passwords? # https://trac.torproject.org/6881 controller = Controller.from_socket_file(socketPath) controller.authenticate() except IOError, exc: if not allowPortConnection: print "Unable to use socket '%s': %s" % (socketPath, exc) elif not allowPortConnection: print "Socket '%s' doesn't exist" % socketPath if not controller and allowPortConnection: # sets up stem connection, prompting for the passphrase if necessary and # sending problems to stdout if they arise authPassword = config.get("startup.controlPassword", CONFIG["startup.controlPassword"]) incorrectPasswordMsg = "Password found in '%s' was incorrect" % configPath controller = _getController(controlAddr, controlPort, authPassword, incorrectPasswordMsg, not allowDetachedStart) # removing references to the controller password so the memory can be freed
def connect(self, settings=False, config=False, tor_status_update_func=None): common.log('Onion', 'connect') # Either use settings that are passed in, or load them from disk if settings: self.settings = settings else: self.settings = Settings(config) self.settings.load() # The Tor controller self.c = None if self.settings.get('connection_type') == 'bundled': if not self.bundle_tor_supported: raise BundledTorNotSupported(strings._('settings_error_bundled_tor_not_supported')) # Create a torrc for this session self.tor_data_directory = tempfile.TemporaryDirectory() if self.system == 'Windows': # Windows needs to use network ports, doesn't support unix sockets torrc_template = open(common.get_resource_path('torrc_template-windows')).read() try: self.tor_control_port = common.get_available_port(1000, 65535) except: raise OSError(strings._('no_available_port')) self.tor_control_socket = None self.tor_cookie_auth_file = os.path.join(self.tor_data_directory.name, 'cookie') try: self.tor_socks_port = common.get_available_port(1000, 65535) except: raise OSError(strings._('no_available_port')) self.tor_torrc = os.path.join(self.tor_data_directory.name, 'torrc') else: # Linux, Mac and BSD can use unix sockets with open(common.get_resource_path('torrc_template')) as f: torrc_template = f.read() self.tor_control_port = None self.tor_control_socket = os.path.join(self.tor_data_directory.name, 'control_socket') self.tor_cookie_auth_file = os.path.join(self.tor_data_directory.name, 'cookie') try: self.tor_socks_port = common.get_available_port(1000, 65535) except: raise OSError(strings._('no_available_port')) self.tor_torrc = os.path.join(self.tor_data_directory.name, 'torrc') torrc_template = torrc_template.replace('{{data_directory}}', self.tor_data_directory.name) torrc_template = torrc_template.replace('{{control_port}}', str(self.tor_control_port)) torrc_template = torrc_template.replace('{{control_socket}}', str(self.tor_control_socket)) torrc_template = torrc_template.replace('{{cookie_auth_file}}', self.tor_cookie_auth_file) torrc_template = torrc_template.replace('{{geo_ip_file}}', self.tor_geo_ip_file_path) torrc_template = torrc_template.replace('{{geo_ipv6_file}}', self.tor_geo_ipv6_file_path) torrc_template = torrc_template.replace('{{socks_port}}', str(self.tor_socks_port)) with open(self.tor_torrc, 'w') as f: f.write(torrc_template) # Bridge support if self.settings.get('tor_bridges_use_obfs4'): f.write('ClientTransportPlugin obfs4 exec {}\n'.format(self.obfs4proxy_file_path)) with open(common.get_resource_path('torrc_template-obfs4')) as o: for line in o: f.write(line) elif self.settings.get('tor_bridges_use_meek_lite_amazon'): f.write('ClientTransportPlugin meek_lite exec {}\n'.format(self.obfs4proxy_file_path)) with open(common.get_resource_path('torrc_template-meek_lite_amazon')) as o: for line in o: f.write(line) elif self.settings.get('tor_bridges_use_meek_lite_azure'): f.write('ClientTransportPlugin meek_lite exec {}\n'.format(self.obfs4proxy_file_path)) with open(common.get_resource_path('torrc_template-meek_lite_azure')) as o: for line in o: f.write(line) if self.settings.get('tor_bridges_use_custom_bridges'): if 'obfs4' in self.settings.get('tor_bridges_use_custom_bridges'): f.write('ClientTransportPlugin obfs4 exec {}\n'.format(self.obfs4proxy_file_path)) elif 'meek_lite' in self.settings.get('tor_bridges_use_custom_bridges'): f.write('ClientTransportPlugin meek_lite exec {}\n'.format(self.obfs4proxy_file_path)) f.write(self.settings.get('tor_bridges_use_custom_bridges')) f.write('\nUseBridges 1') # Execute a tor subprocess start_ts = time.time() if self.system == 'Windows': # In Windows, hide console window when opening tor.exe subprocess startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW self.tor_proc = subprocess.Popen([self.tor_path, '-f', self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo) else: self.tor_proc = subprocess.Popen([self.tor_path, '-f', self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Wait for the tor controller to start time.sleep(2) # Connect to the controller try: if self.system == 'Windows': self.c = Controller.from_port(port=self.tor_control_port) self.c.authenticate() else: self.c = Controller.from_socket_file(path=self.tor_control_socket) self.c.authenticate() except Exception as e: raise BundledTorBroken(strings._('settings_error_bundled_tor_broken', True).format(e.args[0])) while True: try: res = self.c.get_info("status/bootstrap-phase") except SocketClosed: raise BundledTorCanceled() res_parts = shlex.split(res) progress = res_parts[2].split('=')[1] summary = res_parts[4].split('=')[1] # "\033[K" clears the rest of the line print("{}: {}% - {}{}".format(strings._('connecting_to_tor'), progress, summary, "\033[K"), end="\r") if callable(tor_status_update_func): if not tor_status_update_func(progress, summary): # If the dialog was canceled, stop connecting to Tor common.log('Onion', 'connect', 'tor_status_update_func returned false, canceling connecting to Tor') print() return False if summary == 'Done': print("") break time.sleep(0.2) # If using bridges, it might take a bit longer to connect to Tor if self.settings.get('tor_bridges_use_custom_bridges') or \ self.settings.get('tor_bridges_use_obfs4') or \ self.settings.get('tor_bridges_use_meek_lite_amazon') or \ self.settings.get('tor_bridges_use_meek_lite_azure'): connect_timeout = 150 else: # Timeout after 120 seconds connect_timeout = 120 if time.time() - start_ts > connect_timeout: print("") self.tor_proc.terminate() raise BundledTorTimeout(strings._('settings_error_bundled_tor_timeout')) elif self.settings.get('connection_type') == 'automatic': # Automatically try to guess the right way to connect to Tor Browser # Try connecting to control port found_tor = False # If the TOR_CONTROL_PORT environment variable is set, use that env_port = os.environ.get('TOR_CONTROL_PORT') if env_port: try: self.c = Controller.from_port(port=int(env_port)) found_tor = True except: pass else: # Otherwise, try default ports for Tor Browser, Tor Messenger, and system tor try: ports = [9151, 9153, 9051] for port in ports: self.c = Controller.from_port(port=port) found_tor = True except: pass # If this still didn't work, try guessing the default socket file path socket_file_path = '' if not found_tor: try: if self.system == 'Darwin': socket_file_path = os.path.expanduser('~/Library/Application Support/TorBrowser-Data/Tor/control.socket') self.c = Controller.from_socket_file(path=socket_file_path) found_tor = True except: pass # If connecting to default control ports failed, so let's try # guessing the socket file name next if not found_tor: try: if self.system == 'Linux' or self.system == 'BSD': socket_file_path = '/run/user/{}/Tor/control.socket'.format(os.geteuid()) elif self.system == 'Darwin': socket_file_path = '/run/user/{}/Tor/control.socket'.format(os.geteuid()) elif self.system == 'Windows': # Windows doesn't support unix sockets raise TorErrorAutomatic(strings._('settings_error_automatic')) self.c = Controller.from_socket_file(path=socket_file_path) except: raise TorErrorAutomatic(strings._('settings_error_automatic')) # Try authenticating try: self.c.authenticate() except: raise TorErrorAutomatic(strings._('settings_error_automatic')) else: # Use specific settings to connect to tor # Try connecting try: if self.settings.get('connection_type') == 'control_port': self.c = Controller.from_port(address=self.settings.get('control_port_address'), port=self.settings.get('control_port_port')) elif self.settings.get('connection_type') == 'socket_file': self.c = Controller.from_socket_file(path=self.settings.get('socket_file_path')) else: raise TorErrorInvalidSetting(strings._("settings_error_unknown")) except: if self.settings.get('connection_type') == 'control_port': raise TorErrorSocketPort(strings._("settings_error_socket_port").format(self.settings.get('control_port_address'), self.settings.get('control_port_port'))) else: raise TorErrorSocketFile(strings._("settings_error_socket_file").format(self.settings.get('socket_file_path'))) # Try authenticating try: if self.settings.get('auth_type') == 'no_auth': self.c.authenticate() elif self.settings.get('auth_type') == 'password': self.c.authenticate(self.settings.get('auth_password')) else: raise TorErrorInvalidSetting(strings._("settings_error_unknown")) except MissingPassword: raise TorErrorMissingPassword(strings._('settings_error_missing_password')) except UnreadableCookieFile: raise TorErrorUnreadableCookieFile(strings._('settings_error_unreadable_cookie_file')) except AuthenticationFailure: raise TorErrorAuthError(strings._('settings_error_auth').format(self.settings.get('control_port_address'), self.settings.get('control_port_port'))) # If we made it this far, we should be connected to Tor self.connected_to_tor = True # Get the tor version self.tor_version = self.c.get_version().version_str # Do the versions of stem and tor that I'm using support ephemeral onion services? list_ephemeral_hidden_services = getattr(self.c, "list_ephemeral_hidden_services", None) self.supports_ephemeral = callable(list_ephemeral_hidden_services) and self.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.service_id self.c.remove_ephemeral_hidden_service(tmp_service_id) self.supports_stealth = True except: # ephemeral stealth onion services are not supported self.supports_stealth = False
#import re import platform from influxdb import InfluxDBClient from stem.control import EventType, Controller INFLUXDB_HOST = "influxdb1" INFLUXDB_PORT = 8086 INFLUXDB_USER = "******" INFLUXDB_PASSWORD = "******" INFLUXDB_DATABASE = "tor" with Controller.from_socket_file() as controller: controller.authenticate() # p = re.compile('(?P<read>\d+)\,(?P<write>\d+)$') bytes_read = controller.get_info("traffic/read") bytes_written = controller.get_info("traffic/written") bandwidth = controller.get_info("bw-event-cache") #m = p.search(bandwidth) tx = 0 rx = 0 i = 0 for value in (bandwidth.split(' '))[-60:]: value_split = value.split(',') rx += int(value_split[0]) tx += int(value_split[1]) i += 1 rx /= i tx /= i
#!/usr/bin/python from stem.control import Controller from os import getenv from re import match PORT = getenv('TORCONTROL') try: controller = Controller.from_socket_file(path=PORT) except: try: controller = Controller.from_port(port=int(PORT)) except: try: controller = Controller.from_port(address=PORT) except: if not PORT: print 'Failed to connect to TORCONTROL=%s' % PORT raise SystemExit(1) res = match('([^/:]*):([0-9]*)$', PORT).groups() if res[0]: if res[1]: controller = Controller.from_port(address=res[0],port=int(res[1])) else: controller = Controller.from_port(address=res[0]) else: controller = Controller.from_port(port=int(res[1])) controller.authenticate() if __name__ == '__main__':
def connect( self, custom_settings=None, config=None, tor_status_update_func=None, connect_timeout=120, local_only=False, ): if local_only: self.common.log("Onion", "connect", "--local-only, so skip trying to connect") return # Either use settings that are passed in, or use them from common if custom_settings: self.settings = custom_settings elif config: self.common.load_settings(config) self.settings = self.common.settings else: self.common.load_settings() self.settings = self.common.settings self.common.log( "Onion", "connect", f"connection_type={self.settings.get('connection_type')}", ) # The Tor controller self.c = None if self.settings.get("connection_type") == "bundled": # Create a torrc for this session if self.use_tmp_dir: self.tor_data_directory = tempfile.TemporaryDirectory( dir=self.common.build_tmp_dir()) self.tor_data_directory_name = self.tor_data_directory.name else: self.tor_data_directory_name = self.common.build_tor_dir() self.common.log( "Onion", "connect", f"tor_data_directory_name={self.tor_data_directory_name}", ) # Create the torrc with open(self.common.get_resource_path("torrc_template")) as f: torrc_template = f.read() self.tor_cookie_auth_file = os.path.join( self.tor_data_directory_name, "cookie") try: self.tor_socks_port = self.common.get_available_port( 1000, 65535) except Exception: print("OnionShare port not available") raise PortNotAvailable() self.tor_torrc = os.path.join(self.tor_data_directory_name, "torrc") # If there is an existing OnionShare tor process, kill it for proc in psutil.process_iter(["pid", "name", "username"]): try: cmdline = proc.cmdline() if (cmdline[0] == self.tor_path and cmdline[1] == "-f" and cmdline[2] == self.tor_torrc): self.common.log( "Onion", "connect", "found a stale tor process, killing it") proc.terminate() proc.wait() break except Exception: pass if self.common.platform == "Windows" or self.common.platform == "Darwin": # Windows doesn't support unix sockets, so it must use a network port. # macOS can't use unix sockets either because socket filenames are limited to # 100 chars, and the macOS sandbox forces us to put the socket file in a place # with a really long path. torrc_template += "ControlPort {{control_port}}\n" try: self.tor_control_port = self.common.get_available_port( 1000, 65535) except Exception: print("OnionShare port not available") raise PortNotAvailable() self.tor_control_socket = None else: # Linux and BSD can use unix sockets torrc_template += "ControlSocket {{control_socket}}\n" self.tor_control_port = None self.tor_control_socket = os.path.join( self.tor_data_directory_name, "control_socket") torrc_template = torrc_template.replace( "{{data_directory}}", self.tor_data_directory_name) torrc_template = torrc_template.replace("{{control_port}}", str(self.tor_control_port)) torrc_template = torrc_template.replace( "{{control_socket}}", str(self.tor_control_socket)) torrc_template = torrc_template.replace("{{cookie_auth_file}}", self.tor_cookie_auth_file) torrc_template = torrc_template.replace("{{geo_ip_file}}", self.tor_geo_ip_file_path) torrc_template = torrc_template.replace( "{{geo_ipv6_file}}", self.tor_geo_ipv6_file_path) torrc_template = torrc_template.replace("{{socks_port}}", str(self.tor_socks_port)) torrc_template = torrc_template.replace( "{{obfs4proxy_path}}", str(self.obfs4proxy_file_path)) torrc_template = torrc_template.replace( "{{snowflake_path}}", str(self.snowflake_file_path)) with open(self.tor_torrc, "w") as f: self.common.log("Onion", "connect", "Writing torrc template file") f.write(torrc_template) # Bridge support if self.settings.get("bridges_enabled"): f.write("\nUseBridges 1\n") if self.settings.get("bridges_type") == "built-in": use_torrc_bridge_templates = False builtin_bridge_type = self.settings.get( "bridges_builtin_pt") # Use built-inbridges stored in settings, if they are there already. # They are probably newer than that of our hardcoded copies. if self.settings.get("bridges_builtin"): try: for line in self.settings.get( "bridges_builtin" )[builtin_bridge_type]: if line.strip() != "": f.write(f"Bridge {line}\n") self.common.log( "Onion", "connect", "Wrote in the built-in bridges from OnionShare settings", ) except KeyError: # Somehow we had built-in bridges in our settings, but # not for this bridge type. Fall back to using the hard- # coded templates. use_torrc_bridge_templates = True else: use_torrc_bridge_templates = True if use_torrc_bridge_templates: if builtin_bridge_type == "obfs4": with open( self.common.get_resource_path( "torrc_template-obfs4")) as o: f.write(o.read()) elif builtin_bridge_type == "meek-azure": with open( self.common.get_resource_path( "torrc_template-meek_lite_azure") ) as o: f.write(o.read()) elif builtin_bridge_type == "snowflake": with open( self.common.get_resource_path( "torrc_template-snowflake")) as o: f.write(o.read()) self.common.log( "Onion", "connect", "Wrote in the built-in bridges from torrc templates", ) elif self.settings.get("bridges_type") == "moat": for line in self.settings.get("bridges_moat").split( "\n"): if line.strip() != "": f.write(f"Bridge {line}\n") elif self.settings.get("bridges_type") == "custom": for line in self.settings.get("bridges_custom").split( "\n"): if line.strip() != "": f.write(f"Bridge {line}\n") # Execute a tor subprocess self.common.log("Onion", "connect", f"starting {self.tor_path} subprocess") start_ts = time.time() if self.common.platform == "Windows": # In Windows, hide console window when opening tor.exe subprocess startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW self.tor_proc = subprocess.Popen( [self.tor_path, "-f", self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo, ) else: if self.common.is_snapcraft(): env = None else: env = {"LD_LIBRARY_PATH": os.path.dirname(self.tor_path)} self.tor_proc = subprocess.Popen( [self.tor_path, "-f", self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, ) # Wait for the tor controller to start self.common.log("Onion", "connect", f"tor pid: {self.tor_proc.pid}") time.sleep(2) return_code = self.tor_proc.poll() if return_code != None: self.common.log( "Onion", "connect", f"tor process has terminated early: {return_code}") # Connect to the controller self.common.log("Onion", "connect", "authenticating to tor controller") try: if (self.common.platform == "Windows" or self.common.platform == "Darwin"): self.c = Controller.from_port(port=self.tor_control_port) self.c.authenticate() else: self.c = Controller.from_socket_file( path=self.tor_control_socket) self.c.authenticate() except Exception as e: print("OnionShare could not connect to Tor:\n{}".format( e.args[0])) print(traceback.format_exc()) raise BundledTorBroken(e.args[0]) while True: try: res = self.c.get_info("status/bootstrap-phase") except SocketClosed: raise BundledTorCanceled() res_parts = shlex.split(res) progress = res_parts[2].split("=")[1] summary = res_parts[4].split("=")[1] # "\033[K" clears the rest of the line print( f"\rConnecting to the Tor network: {progress}% - {summary}\033[K", end="", ) if callable(tor_status_update_func): if not tor_status_update_func(progress, summary): # If the dialog was canceled, stop connecting to Tor self.common.log( "Onion", "connect", "tor_status_update_func returned false, canceling connecting to Tor", ) print() return False if summary == "Done": print("") break time.sleep(0.2) # If using bridges, it might take a bit longer to connect to Tor if self.settings.get("bridges_enabled"): # Only override timeout if a custom timeout has not been passed in if connect_timeout == 120: connect_timeout = 150 if time.time() - start_ts > connect_timeout: print("") try: self.tor_proc.terminate() print( "Taking too long to connect to Tor. Maybe you aren't connected to the Internet, or have an inaccurate system clock?" ) raise BundledTorTimeout() except FileNotFoundError: pass elif self.settings.get("connection_type") == "automatic": # Automatically try to guess the right way to connect to Tor Browser automatic_error = "Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?" # Try connecting to control port found_tor = False # If the TOR_CONTROL_PORT environment variable is set, use that env_port = os.environ.get("TOR_CONTROL_PORT") if env_port: try: self.c = Controller.from_port(port=int(env_port)) found_tor = True except Exception: pass else: # Otherwise, try default ports for Tor Browser, Tor Messenger, and system tor try: ports = [9151, 9153, 9051] for port in ports: self.c = Controller.from_port(port=port) found_tor = True except Exception: pass # If this still didn't work, try guessing the default socket file path socket_file_path = "" if not found_tor: try: if self.common.platform == "Darwin": socket_file_path = os.path.expanduser( "~/Library/Application Support/TorBrowser-Data/Tor/control.socket" ) self.c = Controller.from_socket_file( path=socket_file_path) found_tor = True except Exception: pass # If connecting to default control ports failed, so let's try # guessing the socket file name next if not found_tor: try: if self.common.platform == "Linux" or self.common.platform == "BSD": socket_file_path = ( f"/run/user/{os.geteuid()}/Tor/control.socket") elif self.common.platform == "Darwin": socket_file_path = ( f"/run/user/{os.geteuid()}/Tor/control.socket") elif self.common.platform == "Windows": # Windows doesn't support unix sockets print(automatic_error) raise TorErrorAutomatic() self.c = Controller.from_socket_file(path=socket_file_path) except Exception: print(automatic_error) raise TorErrorAutomatic() # Try authenticating try: self.c.authenticate() except Exception: print(automatic_error) raise TorErrorAutomatic() else: # Use specific settings to connect to tor invalid_settings_error = "Can't connect to Tor controller because your settings don't make sense." # Try connecting try: if self.settings.get("connection_type") == "control_port": self.c = Controller.from_port( address=self.settings.get("control_port_address"), port=self.settings.get("control_port_port"), ) elif self.settings.get("connection_type") == "socket_file": self.c = Controller.from_socket_file( path=self.settings.get("socket_file_path")) else: print(invalid_settings_error) raise TorErrorInvalidSetting() except Exception: if self.settings.get("connection_type") == "control_port": print( "Can't connect to the Tor controller at {}:{}.".format( self.settings.get("control_port_address"), self.settings.get("control_port_port"), )) raise TorErrorSocketPort( self.settings.get("control_port_address"), self.settings.get("control_port_port"), ) print( "Can't connect to the Tor controller using socket file {}." .format(self.settings.get("socket_file_path"))) raise TorErrorSocketFile(self.settings.get("socket_file_path")) # Try authenticating try: if self.settings.get("auth_type") == "no_auth": self.c.authenticate() elif self.settings.get("auth_type") == "password": self.c.authenticate(self.settings.get("auth_password")) else: print(invalid_settings_error) raise TorErrorInvalidSetting() except MissingPassword: print( "Connected to Tor controller, but it requires a password to authenticate." ) raise TorErrorMissingPassword() except UnreadableCookieFile: print( "Connected to the Tor controller, but password may be wrong, or your user is not permitted to read the cookie file." ) raise TorErrorUnreadableCookieFile() except AuthenticationFailure: print( "Connected to {}:{}, but can't authenticate. Maybe this isn't a Tor controller?" .format( self.settings.get("control_port_address"), self.settings.get("control_port_port"), )) raise TorErrorAuthError( self.settings.get("control_port_address"), self.settings.get("control_port_port"), ) # If we made it this far, we should be connected to Tor self.connected_to_tor = True # Get the tor version self.tor_version = self.c.get_version().version_str self.common.log("Onion", "connect", f"Connected to tor {self.tor_version}") # Do the versions of stem and tor that I'm using support ephemeral onion services? list_ephemeral_hidden_services = getattr( self.c, "list_ephemeral_hidden_services", None) self.supports_ephemeral = (callable(list_ephemeral_hidden_services) and self.tor_version >= "0.2.7.1") # Do the versions of stem and tor that I'm using support v3 stealth onion services? try: res = self.c.create_ephemeral_hidden_service( {1: 1}, basic_auth=None, await_publication=False, key_type="NEW", key_content="ED25519-V3", client_auth_v3= "E2GOT5LTUTP3OAMRCRXO4GSH6VKJEUOXZQUC336SRKAHTTT5OVSA", ) tmp_service_id = res.service_id self.c.remove_ephemeral_hidden_service(tmp_service_id) self.supports_stealth = True except Exception: # ephemeral stealth onion services are not supported self.supports_stealth = False # Does this version of Tor support next-gen ('v3') onions? # Note, this is the version of Tor where this bug was fixed: # https://trac.torproject.org/projects/tor/ticket/28619 self.supports_v3_onions = self.tor_version >= Version("0.3.5.7") # Now that we are connected to Tor, if we are using built-in bridges, # update them with the latest copy available from the Tor API if (self.settings.get("bridges_enabled") and self.settings.get("bridges_type") == "built-in"): self.update_builtin_bridges()
def main(): """ Entry point when invoked over the command line. """ setproctitle('onionbalance') args = parse_cmd_args().parse_args() config_file_options = settings.parse_config_file(args.config) # Update global configuration with options specified in the config file for setting in dir(config): if setting.isupper() and config_file_options.get(setting): setattr(config, setting, config_file_options.get(setting)) # Override the log level if specified on the command line. if args.verbosity: config.LOG_LEVEL = args.verbosity.upper() # Write log file if configured in environment variable or config file if config.LOG_LOCATION: log.setup_file_logger(config.LOG_LOCATION) logger.setLevel(logging.__dict__[config.LOG_LEVEL.upper()]) # Create a connection to the Tor unix domain control socket or control port try: tor_socket = (args.socket or config.TOR_CONTROL_SOCKET) tor_address = (args.ip or config.TOR_ADDRESS) tor_port = (args.port or config.TOR_PORT) try: controller = Controller.from_socket_file(path=tor_socket) logger.debug("Successfully connected to the Tor control socket " "%s.", tor_socket) except stem.SocketError: logger.debug("Unable to connect to the Tor control socket %s.", tor_socket) controller = Controller.from_port(address=tor_address, port=tor_port) logger.debug("Successfully connected to the Tor control port.") except stem.SocketError as exc: logger.error("Unable to connect to Tor control socket or port: %s", exc) sys.exit(1) try: controller.authenticate(password=config.TOR_CONTROL_PASSWORD) except stem.connection.AuthenticationFailure as exc: logger.error("Unable to authenticate on the Tor control connection: " "%s", exc) sys.exit(1) else: logger.debug("Successfully authenticated on the Tor control " "connection.") status_socket = status.StatusSocket(config.STATUS_SOCKET_LOCATION) eventhandler.SignalHandler(controller, status_socket) # Disable no-member due to bug with "Instance of 'Enum' has no * member" # pylint: disable=no-member # Check that the Tor client supports the HSPOST control port command if not controller.get_version() >= stem.version.Requirement.HSPOST: logger.error("A Tor version >= %s is required. You may need to " "compile Tor from source or install a package from " "the experimental Tor repository.", stem.version.Requirement.HSPOST) sys.exit(1) # Load the keys and config for each onion service settings.initialize_services(controller, config_file_options.get('services')) # Finished parsing all the config file. handler = eventhandler.EventHandler() controller.add_event_listener(handler.new_status, EventType.STATUS_GENERAL) controller.add_event_listener(handler.new_desc, EventType.HS_DESC) controller.add_event_listener(handler.new_desc_content, EventType.HS_DESC_CONTENT) # Schedule descriptor fetch and upload events scheduler.add_job(config.REFRESH_INTERVAL, fetch_instance_descriptors, controller) scheduler.add_job(config.PUBLISH_CHECK_INTERVAL, publish_all_descriptors) # Run initial fetch of HS instance descriptors scheduler.run_all(delay_seconds=config.INITIAL_DELAY) # Begin main loop to poll for HS descriptors scheduler.run_forever() return 0
def connect(self, settings=False, tor_status_update_func=None): common.log('Onion', 'connect') # Either use settings that are passed in, or load them from disk if settings: self.settings = settings else: self.settings = Settings() self.settings.load() # The Tor controller self.c = None if self.settings.get('connection_type') == 'bundled': if not self.bundle_tor_supported: raise BundledTorNotSupported( strings._('settings_error_bundled_tor_not_supported')) # Create a torrc for this session self.tor_data_directory = tempfile.TemporaryDirectory() if self.system == 'Windows': # Windows needs to use network ports, doesn't support unix sockets torrc_template = open( common.get_resource_path('torrc_template-windows')).read() self.tor_control_port = common.get_available_port(1000, 65535) self.tor_control_socket = None self.tor_cookie_auth_file = os.path.join( self.tor_data_directory.name, 'cookie') self.tor_socks_port = common.get_available_port(1000, 65535) self.tor_torrc = os.path.join(self.tor_data_directory.name, 'torrc') else: # Linux and Mac can use unix sockets with open(common.get_resource_path('torrc_template')) as f: torrc_template = f.read() self.tor_control_port = None self.tor_control_socket = os.path.join( self.tor_data_directory.name, 'control_socket') self.tor_cookie_auth_file = os.path.join( self.tor_data_directory.name, 'cookie') self.tor_socks_port = common.get_available_port(1000, 65535) self.tor_torrc = os.path.join(self.tor_data_directory.name, 'torrc') torrc_template = torrc_template.replace( '{{data_directory}}', self.tor_data_directory.name) torrc_template = torrc_template.replace('{{control_port}}', str(self.tor_control_port)) torrc_template = torrc_template.replace( '{{control_socket}}', str(self.tor_control_socket)) torrc_template = torrc_template.replace('{{cookie_auth_file}}', self.tor_cookie_auth_file) torrc_template = torrc_template.replace('{{geo_ip_file}}', self.tor_geo_ip_file_path) torrc_template = torrc_template.replace( '{{geo_ipv6_file}}', self.tor_geo_ipv6_file_path) torrc_template = torrc_template.replace('{{socks_port}}', str(self.tor_socks_port)) with open(self.tor_torrc, 'w') as f: f.write(torrc_template) # Execute a tor subprocess start_ts = time.time() if self.system == 'Windows': # In Windows, hide console window when opening tor.exe subprocess startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW self.tor_proc = subprocess.Popen( [self.tor_path, '-f', self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo) else: self.tor_proc = subprocess.Popen( [self.tor_path, '-f', self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Wait for the tor controller to start time.sleep(2) # Connect to the controller try: if self.system == 'Windows': self.c = Controller.from_port(port=self.tor_control_port) self.c.authenticate() else: self.c = Controller.from_socket_file( path=self.tor_control_socket) self.c.authenticate() except Exception as e: raise BundledTorBroken( strings._('settings_error_bundled_tor_broken', True).format(e.args[0])) while True: try: res = self.c.get_info("status/bootstrap-phase") except SocketClosed: raise BundledTorCanceled() res_parts = shlex.split(res) progress = res_parts[2].split('=')[1] summary = res_parts[4].split('=')[1] # "\033[K" clears the rest of the line print("{}: {}% - {}{}".format(strings._('connecting_to_tor'), progress, summary, "\033[K"), end="\r") if callable(tor_status_update_func): if not tor_status_update_func(progress, summary): # If the dialog was canceled, stop connecting to Tor common.log( 'Onion', 'connect', 'tor_status_update_func returned false, canceling connecting to Tor' ) print() return False if summary == 'Done': print("") break time.sleep(0.2) # Timeout after 45 seconds if time.time() - start_ts > 45: print("") self.tor_proc.terminate() raise BundledTorTimeout( strings._('settings_error_bundled_tor_timeout')) elif self.settings.get('connection_type') == 'automatic': # Automatically try to guess the right way to connect to Tor Browser # Try connecting to control port found_tor = False # If the TOR_CONTROL_PORT environment variable is set, use that env_port = os.environ.get('TOR_CONTROL_PORT') if env_port: try: self.c = Controller.from_port(port=int(env_port)) found_tor = True except: pass else: # Otherwise, try default ports for Tor Browser, Tor Messenger, and system tor try: ports = [9151, 9153, 9051] for port in ports: self.c = Controller.from_port(port=port) found_tor = True except: pass # If this still didn't work, try guessing the default socket file path socket_file_path = '' if not found_tor: try: if self.system == 'Darwin': socket_file_path = os.path.expanduser( '~/Library/Application Support/TorBrowser-Data/Tor/control.socket' ) self.c = Controller.from_socket_file( path=socket_file_path) found_tor = True except: pass # If connecting to default control ports failed, so let's try # guessing the socket file name next if not found_tor: try: if self.system == 'Linux': socket_file_path = '/run/user/{}/Tor/control.socket'.format( os.geteuid()) elif self.system == 'Darwin': socket_file_path = '/run/user/{}/Tor/control.socket'.format( os.geteuid()) elif self.system == 'Windows': # Windows doesn't support unix sockets raise TorErrorAutomatic( strings._('settings_error_automatic')) self.c = Controller.from_socket_file(path=socket_file_path) except: raise TorErrorAutomatic( strings._('settings_error_automatic')) # Try authenticating try: self.c.authenticate() except: raise TorErrorAutomatic(strings._('settings_error_automatic')) else: # Use specific settings to connect to tor # Try connecting try: if self.settings.get('connection_type') == 'control_port': self.c = Controller.from_port( address=self.settings.get('control_port_address'), port=self.settings.get('control_port_port')) elif self.settings.get('connection_type') == 'socket_file': self.c = Controller.from_socket_file( path=self.settings.get('socket_file_path')) else: raise TorErrorInvalidSetting( strings._("settings_error_unknown")) except: if self.settings.get('connection_type') == 'control_port': raise TorErrorSocketPort( strings._("settings_error_socket_port").format( self.settings.get('control_port_address'), self.settings.get('control_port_port'))) else: raise TorErrorSocketFile( strings._("settings_error_socket_file").format( self.settings.get('socket_file_path'))) # Try authenticating try: if self.settings.get('auth_type') == 'no_auth': self.c.authenticate() elif self.settings.get('auth_type') == 'password': self.c.authenticate(self.settings.get('auth_password')) else: raise TorErrorInvalidSetting( strings._("settings_error_unknown")) except MissingPassword: raise TorErrorMissingPassword( strings._('settings_error_missing_password')) except UnreadableCookieFile: raise TorErrorUnreadableCookieFile( strings._('settings_error_unreadable_cookie_file')) except AuthenticationFailure: raise TorErrorAuthError( strings._('settings_error_auth').format( self.settings.get('control_port_address'), self.settings.get('control_port_port'))) # If we made it this far, we should be connected to Tor self.connected_to_tor = True # Get the tor version self.tor_version = self.c.get_version().version_str # Do the versions of stem and tor that I'm using support ephemeral onion services? list_ephemeral_hidden_services = getattr( self.c, "list_ephemeral_hidden_services", None) self.supports_ephemeral = callable( list_ephemeral_hidden_services) and self.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: # ephemeral stealth onion services are not supported self.supports_stealth = False
def __init__(self, transparent_torification=False, stealth=False, settings=False): self.transparent_torification = transparent_torification self.stealth = stealth # Either use settings that are passed in, or load them from disk if settings: self.settings = settings else: self.settings = Settings() self.settings.load() # files and dirs to delete on shutdown self.cleanup_filenames = [] self.service_id = None # Try to connect to Tor self.c = None if self.settings.get('connection_type') == 'automatic': # Automatically try to guess the right way to connect to Tor Browser p = platform.system() # Try connecting to control port found_tor = False # If the TOR_CONTROL_PORT environment variable is set, use that env_port = os.environ.get('TOR_CONTROL_PORT') if env_port: try: self.c = Controller.from_port(port=int(env_port)) found_tor = True except: pass else: # Otherwise, try default ports for Tor Browser, Tor Messenger, and system tor try: ports = [9151, 9153, 9051] for port in ports: self.c = Controller.from_port(port=port) found_tor = True except: pass # If this still didn't work, try guessing the default socket file path socket_file_path = '' if not found_tor: try: if p == 'Darwin': socket_file_path = os.path.expanduser( '~/Library/Application Support/TorBrowser-Data/Tor/control.socket' ) self.c = Controller.from_socket_file( path=socket_file_path) found_tor = True except: pass # If connecting to default control ports failed, so let's try # guessing the socket file name next if not found_tor: try: if p == 'Linux': socket_file_path = '/run/user/{}/Tor/control.socket'.format( os.geteuid()) elif p == 'Darwin': # TODO: figure out the unix socket path in OS X socket_file_path = '/run/user/{}/Tor/control.socket'.format( os.geteuid()) elif p == 'Windows': # Windows doesn't support unix sockets raise TorErrorAutomatic( strings._('settings_error_automatic')) self.c = Controller.from_socket_file(path=socket_file_path) except: raise TorErrorAutomatic( strings._('settings_error_automatic')) # Try authenticating try: self.c.authenticate() except: raise TorErrorAutomatic(strings._('settings_error_automatic')) else: # Use specific settings to connect to tor # Try connecting try: if self.settings.get('connection_type') == 'control_port': self.c = Controller.from_port( address=self.settings.get('control_port_address'), port=self.settings.get('control_port_port')) elif self.settings.get('connection_type') == 'socket_file': self.c = Controller.from_socket_file( path=self.settings.get('socket_file_path')) else: raise TorErrorInvalidSetting( strings._("settings_error_unknown")) except: if self.settings.get('connection_type') == 'control_port': raise TorErrorSocketPort( strings._("settings_error_socket_port").format( self.settings.get('control_port_address'), self.settings.get('control_port_port'))) else: raise TorErrorSocketFile( strings._("settings_error_socket_file").format( self.settings.get('socket_file_path'))) # Try authenticating try: if self.settings.get('auth_type') == 'no_auth': self.c.authenticate() elif self.settings.get('auth_type') == 'password': self.c.authenticate(self.settings.get('auth_password')) else: raise TorErrorInvalidSetting( strings._("settings_error_unknown")) except MissingPassword: raise TorErrorMissingPassword( strings._('settings_error_missing_password')) except UnreadableCookieFile: raise TorErrorUnreadableCookieFile( strings._('settings_error_unreadable_cookie_file')) except AuthenticationFailure: raise TorErrorAuthError( strings._('settings_error_auth').format( self.settings.get('control_port_address'), self.settings.get('control_port_port'))) # get the tor version self.tor_version = self.c.get_version().version_str # do the versions of stem and tor that I'm using support ephemeral onion services? list_ephemeral_hidden_services = getattr( self.c, "list_ephemeral_hidden_services", None) self.supports_ephemeral = callable( list_ephemeral_hidden_services) and self.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: # ephemeral stealth onion services are not supported self.supports_stealth = False
def _get_controller_socket(args): return Controller.from_socket_file(path=args.ctrl_socket)
def connect( self, custom_settings=False, config=False, tor_status_update_func=None, connect_timeout=120, ): self.common.log("Onion", "connect") # Either use settings that are passed in, or use them from common if custom_settings: self.settings = custom_settings elif config: self.common.load_settings(config) self.settings = self.common.settings else: self.common.load_settings() self.settings = self.common.settings strings.load_strings(self.common) # The Tor controller self.c = None if self.settings.get("connection_type") == "bundled": if not self.bundle_tor_supported: raise BundledTorNotSupported( strings._("settings_error_bundled_tor_not_supported") ) # Create a torrc for this session self.tor_data_directory = tempfile.TemporaryDirectory( dir=self.common.build_data_dir() ) self.common.log( "Onion", "connect", "tor_data_directory={}".format(self.tor_data_directory.name), ) # Create the torrc with open(self.common.get_resource_path("torrc_template")) as f: torrc_template = f.read() self.tor_cookie_auth_file = os.path.join( self.tor_data_directory.name, "cookie" ) try: self.tor_socks_port = self.common.get_available_port(1000, 65535) except: raise OSError(strings._("no_available_port")) self.tor_torrc = os.path.join(self.tor_data_directory.name, "torrc") if self.common.platform == "Windows" or self.common.platform == "Darwin": # Windows doesn't support unix sockets, so it must use a network port. # macOS can't use unix sockets either because socket filenames are limited to # 100 chars, and the macOS sandbox forces us to put the socket file in a place # with a really long path. torrc_template += "ControlPort {{control_port}}\n" try: self.tor_control_port = self.common.get_available_port(1000, 65535) except: raise OSError(strings._("no_available_port")) self.tor_control_socket = None else: # Linux and BSD can use unix sockets torrc_template += "ControlSocket {{control_socket}}\n" self.tor_control_port = None self.tor_control_socket = os.path.join( self.tor_data_directory.name, "control_socket" ) torrc_template = torrc_template.replace( "{{data_directory}}", self.tor_data_directory.name ) torrc_template = torrc_template.replace( "{{control_port}}", str(self.tor_control_port) ) torrc_template = torrc_template.replace( "{{control_socket}}", str(self.tor_control_socket) ) torrc_template = torrc_template.replace( "{{cookie_auth_file}}", self.tor_cookie_auth_file ) torrc_template = torrc_template.replace( "{{geo_ip_file}}", self.tor_geo_ip_file_path ) torrc_template = torrc_template.replace( "{{geo_ipv6_file}}", self.tor_geo_ipv6_file_path ) torrc_template = torrc_template.replace( "{{socks_port}}", str(self.tor_socks_port) ) with open(self.tor_torrc, "w") as f: f.write(torrc_template) # Bridge support if self.settings.get("tor_bridges_use_obfs4"): f.write( "ClientTransportPlugin obfs4 exec {}\n".format( self.obfs4proxy_file_path ) ) with open( self.common.get_resource_path("torrc_template-obfs4") ) as o: for line in o: f.write(line) elif self.settings.get("tor_bridges_use_meek_lite_azure"): f.write( "ClientTransportPlugin meek_lite exec {}\n".format( self.obfs4proxy_file_path ) ) with open( self.common.get_resource_path("torrc_template-meek_lite_azure") ) as o: for line in o: f.write(line) if self.settings.get("tor_bridges_use_custom_bridges"): if "obfs4" in self.settings.get("tor_bridges_use_custom_bridges"): f.write( "ClientTransportPlugin obfs4 exec {}\n".format( self.obfs4proxy_file_path ) ) elif "meek_lite" in self.settings.get( "tor_bridges_use_custom_bridges" ): f.write( "ClientTransportPlugin meek_lite exec {}\n".format( self.obfs4proxy_file_path ) ) f.write(self.settings.get("tor_bridges_use_custom_bridges")) f.write("\nUseBridges 1") # Execute a tor subprocess start_ts = time.time() if self.common.platform == "Windows": # In Windows, hide console window when opening tor.exe subprocess startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW self.tor_proc = subprocess.Popen( [self.tor_path, "-f", self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo, ) else: self.tor_proc = subprocess.Popen( [self.tor_path, "-f", self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) # Wait for the tor controller to start time.sleep(2) # Connect to the controller try: if ( self.common.platform == "Windows" or self.common.platform == "Darwin" ): self.c = Controller.from_port(port=self.tor_control_port) self.c.authenticate() else: self.c = Controller.from_socket_file(path=self.tor_control_socket) self.c.authenticate() except Exception as e: raise BundledTorBroken( strings._("settings_error_bundled_tor_broken").format(e.args[0]) ) while True: try: res = self.c.get_info("status/bootstrap-phase") except SocketClosed: raise BundledTorCanceled() res_parts = shlex.split(res) progress = res_parts[2].split("=")[1] summary = res_parts[4].split("=")[1] # "\033[K" clears the rest of the line print( "Connecting to the Tor network: {}% - {}{}".format( progress, summary, "\033[K" ), end="\r", ) if callable(tor_status_update_func): if not tor_status_update_func(progress, summary): # If the dialog was canceled, stop connecting to Tor self.common.log( "Onion", "connect", "tor_status_update_func returned false, canceling connecting to Tor", ) print() return False if summary == "Done": print("") break time.sleep(0.2) # If using bridges, it might take a bit longer to connect to Tor if ( self.settings.get("tor_bridges_use_custom_bridges") or self.settings.get("tor_bridges_use_obfs4") or self.settings.get("tor_bridges_use_meek_lite_azure") ): # Only override timeout if a custom timeout has not been passed in if connect_timeout == 120: connect_timeout = 150 if time.time() - start_ts > connect_timeout: print("") try: self.tor_proc.terminate() raise BundledTorTimeout( strings._("settings_error_bundled_tor_timeout") ) except FileNotFoundError: pass elif self.settings.get("connection_type") == "automatic": # Automatically try to guess the right way to connect to Tor Browser # Try connecting to control port found_tor = False # If the TOR_CONTROL_PORT environment variable is set, use that env_port = os.environ.get("TOR_CONTROL_PORT") if env_port: try: self.c = Controller.from_port(port=int(env_port)) found_tor = True except: pass else: # Otherwise, try default ports for Tor Browser, Tor Messenger, and system tor try: ports = [9151, 9153, 9051] for port in ports: self.c = Controller.from_port(port=port) found_tor = True except: pass # If this still didn't work, try guessing the default socket file path socket_file_path = "" if not found_tor: try: if self.common.platform == "Darwin": socket_file_path = os.path.expanduser( "~/Library/Application Support/TorBrowser-Data/Tor/control.socket" ) self.c = Controller.from_socket_file(path=socket_file_path) found_tor = True except: pass # If connecting to default control ports failed, so let's try # guessing the socket file name next if not found_tor: try: if self.common.platform == "Linux" or self.common.platform == "BSD": socket_file_path = "/run/user/{}/Tor/control.socket".format( os.geteuid() ) elif self.common.platform == "Darwin": socket_file_path = "/run/user/{}/Tor/control.socket".format( os.geteuid() ) elif self.common.platform == "Windows": # Windows doesn't support unix sockets raise TorErrorAutomatic(strings._("settings_error_automatic")) self.c = Controller.from_socket_file(path=socket_file_path) except: raise TorErrorAutomatic(strings._("settings_error_automatic")) # Try authenticating try: self.c.authenticate() except: raise TorErrorAutomatic(strings._("settings_error_automatic")) else: # Use specific settings to connect to tor # Try connecting try: if self.settings.get("connection_type") == "control_port": self.c = Controller.from_port( address=self.settings.get("control_port_address"), port=self.settings.get("control_port_port"), ) elif self.settings.get("connection_type") == "socket_file": self.c = Controller.from_socket_file( path=self.settings.get("socket_file_path") ) else: raise TorErrorInvalidSetting(strings._("settings_error_unknown")) except: if self.settings.get("connection_type") == "control_port": raise TorErrorSocketPort( strings._("settings_error_socket_port").format( self.settings.get("control_port_address"), self.settings.get("control_port_port"), ) ) else: raise TorErrorSocketFile( strings._("settings_error_socket_file").format( self.settings.get("socket_file_path") ) ) # Try authenticating try: if self.settings.get("auth_type") == "no_auth": self.c.authenticate() elif self.settings.get("auth_type") == "password": self.c.authenticate(self.settings.get("auth_password")) else: raise TorErrorInvalidSetting(strings._("settings_error_unknown")) except MissingPassword: raise TorErrorMissingPassword( strings._("settings_error_missing_password") ) except UnreadableCookieFile: raise TorErrorUnreadableCookieFile( strings._("settings_error_unreadable_cookie_file") ) except AuthenticationFailure: raise TorErrorAuthError( strings._("settings_error_auth").format( self.settings.get("control_port_address"), self.settings.get("control_port_port"), ) ) # If we made it this far, we should be connected to Tor self.connected_to_tor = True # Get the tor version self.tor_version = self.c.get_version().version_str self.common.log( "Onion", "connect", "Connected to tor {}".format(self.tor_version) ) # Do the versions of stem and tor that I'm using support ephemeral onion services? list_ephemeral_hidden_services = getattr( self.c, "list_ephemeral_hidden_services", None ) self.supports_ephemeral = ( callable(list_ephemeral_hidden_services) and self.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.service_id self.c.remove_ephemeral_hidden_service(tmp_service_id) self.supports_stealth = True except: # ephemeral stealth onion services are not supported self.supports_stealth = False # Does this version of Tor support next-gen ('v3') onions? # Note, this is the version of Tor where this bug was fixed: # https://trac.torproject.org/projects/tor/ticket/28619 self.supports_v3_onions = self.tor_version >= Version("0.3.5.7")