def test_version_argument(tor_cmd): """ Check that 'tor --version' matches 'GETINFO version'. """ assert_equal('Tor version %s.\n' % test.tor_version(), run_tor(tor_cmd, '--version'))
def test_get_server_descriptor(self): """ Basic checks for get_server_descriptor(). """ runner = test.runner.get_runner() if test.tor_version() >= Requirement.MICRODESCRIPTOR_IS_DEFAULT: self.skipTest('(requires server descriptors)') return with runner.get_tor_controller() as controller: # we should balk at invalid content self.assertRaises(ValueError, controller.get_server_descriptor, None) self.assertRaises(ValueError, controller.get_server_descriptor, '') self.assertRaises(ValueError, controller.get_server_descriptor, 5) self.assertRaises(ValueError, controller.get_server_descriptor, 'z' * 30) # try with a relay that doesn't exist self.assertRaises(stem.ControllerError, controller.get_server_descriptor, 'blargg') self.assertRaises(stem.ControllerError, controller.get_server_descriptor, '5' * 40) test_relay = self._get_router_status_entry(controller) desc_by_fingerprint = controller.get_server_descriptor(test_relay.fingerprint) desc_by_nickname = controller.get_server_descriptor(test_relay.nickname) self.assertEqual(desc_by_fingerprint, desc_by_nickname)
def test_protocolinfo(self): """ Test that the convenient method protocolinfo() works. """ runner = test.runner.get_runner() with runner.get_tor_controller(False) as controller: protocolinfo = controller.get_protocolinfo() self.assertTrue(isinstance(protocolinfo, stem.response.protocolinfo.ProtocolInfoResponse)) # Doing a sanity test on the ProtocolInfoResponse instance returned. tor_options = runner.get_options() auth_methods = [] if test.runner.Torrc.COOKIE in tor_options: auth_methods.append(stem.response.protocolinfo.AuthMethod.COOKIE) if test.tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE: auth_methods.append(stem.response.protocolinfo.AuthMethod.SAFECOOKIE) if test.runner.Torrc.PASSWORD in tor_options: auth_methods.append(stem.response.protocolinfo.AuthMethod.PASSWORD) if not auth_methods: auth_methods.append(stem.response.protocolinfo.AuthMethod.NONE) self.assertEqual(tuple(auth_methods), protocolinfo.auth_methods)
def assert_matches_test_config(self, protocolinfo_response): """ Makes assertions that the protocolinfo response's attributes match those of the test configuration. """ runner = test.runner.get_runner() tor_options = runner.get_options() auth_methods, auth_cookie_path = [], None if test.runner.Torrc.COOKIE in tor_options: auth_methods.append(stem.response.protocolinfo.AuthMethod.COOKIE) if test.tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE: auth_methods.append( stem.response.protocolinfo.AuthMethod.SAFECOOKIE) chroot_path = runner.get_chroot() auth_cookie_path = runner.get_auth_cookie_path() if chroot_path and auth_cookie_path.startswith(chroot_path): auth_cookie_path = auth_cookie_path[len(chroot_path):] if test.runner.Torrc.PASSWORD in tor_options: auth_methods.append(stem.response.protocolinfo.AuthMethod.PASSWORD) if not auth_methods: auth_methods.append(stem.response.protocolinfo.AuthMethod.NONE) self.assertEqual((), protocolinfo_response.unknown_auth_methods) self.assertEqual(tuple(auth_methods), protocolinfo_response.auth_methods) self.assertEqual(auth_cookie_path, protocolinfo_response.cookie_path)
def test_get_server_descriptors(self): """ Fetches a few descriptors via the get_server_descriptors() method. """ runner = test.runner.get_runner() if test.tor_version() >= Requirement.MICRODESCRIPTOR_IS_DEFAULT: self.skipTest('(requires server descriptors)') return with runner.get_tor_controller() as controller: count = 0 for desc in controller.get_server_descriptors(): self.assertTrue(desc.fingerprint is not None) self.assertTrue(desc.nickname is not None) # Se don't want to take the time to read the whole thing. We already # have another test that reads the full cached descriptors (and takes a # while to do so). count += 1 if count > 10: break
def _can_authenticate(auth_type): """ Checks if a given authentication method can authenticate to our control socket. :param stem.connection.AuthMethod auth_type: authentication method to check :returns: bool that's True if we should be able to authenticate and False otherwise """ runner = test.runner.get_runner() tor_options = runner.get_options() password_auth = test.runner.Torrc.PASSWORD in tor_options cookie_auth = test.runner.Torrc.COOKIE in tor_options safecookie_auth = cookie_auth and test.tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE if not password_auth and not cookie_auth: # open socket, anything but safecookie will work return auth_type != stem.connection.AuthMethod.SAFECOOKIE elif auth_type == stem.connection.AuthMethod.PASSWORD: return password_auth elif auth_type == stem.connection.AuthMethod.COOKIE: return cookie_auth elif auth_type == stem.connection.AuthMethod.SAFECOOKIE: return safecookie_auth else: return False
def _check_tor_version(tor_path): version = test.tor_version(tor_path) version_str = str(version).split()[0] if version.git_commit: return '%s (commit %s)' % (version_str, version.git_commit[:8]) else: return version_str
def version(req_version): """ Skips the test unless we meet the required version. :param stem.version.Version req_version: required tor version for the test """ return needs(lambda: test.tor_version() >= req_version, 'requires %s' % req_version)
def _can_ptrace(): # If we're running a tor version where ptrace is disabled and we didn't # set 'DisableDebuggerAttachment=1' then we can infer that it's disabled. has_option = test.tor_version( ) >= stem.version.Requirement.TORRC_DISABLE_DEBUGGER_ATTACHMENT return not has_option or test.runner.Torrc.PTRACE in test.runner.get_runner( ).get_options()
def test_unanonymous_hidden_service_config_must_match(tor_cmd): """ Checking that startup fails if HiddenServiceNonAnonymousMode and HiddenServiceSingleHopMode don't match. """ try: stem.process.launch_tor_with_config( tor_cmd=tor_cmd, config={'HiddenServiceNonAnonymousMode': '1'}, ) raise AssertionError( "Tor shouldn't start with 'HiddenServiceNonAnonymousMode' set but not 'HiddenServiceSingleHopMode'" ) except OSError as exc: if test.tor_version( ) >= stem.version.Requirement.ADD_ONION_NON_ANONYMOUS: assert_equal( 'Process terminated: HiddenServiceNonAnonymousMode does not provide any server anonymity. It must be used with HiddenServiceSingleHopMode set to 1.', str(exc)) else: assert_equal( "Process terminated: Unknown option 'HiddenServiceNonAnonymousMode'. Failing.", str(exc)) try: stem.process.launch_tor_with_config( tor_cmd=tor_cmd, config={'HiddenServiceSingleHopMode': '1'}, ) raise AssertionError( "Tor shouldn't start with 'HiddenServiceSingleHopMode' set but not 'HiddenServiceNonAnonymousMode'" ) except OSError as exc: if test.tor_version( ) >= stem.version.Requirement.ADD_ONION_NON_ANONYMOUS: assert_equal( 'Process terminated: HiddenServiceSingleHopMode does not provide any server anonymity. It must be used with HiddenServiceNonAnonymousMode set to 1.', str(exc)) else: assert_equal( "Process terminated: Unknown option 'HiddenServiceSingleHopMode'. Failing.", str(exc))
def version_older_than(req_version): """ Skips the test unless we meet a version older than the requested version. :param stem.version.Version req_version: the version that tor should be older than """ return needs(lambda: test.tor_version() < req_version, 'requires %s' % req_version)
def test_version_argument(tor_cmd): """ Check that 'tor --version' matches 'GETINFO version'. """ # We're only interested in the first line of output: # Other lines are about libraries and compilers. tor_version = run_tor(tor_cmd, '--version').split("\n")[0] assert_equal('Tor version %s.' % test.tor_version(), tor_version)
def test_get_version(self): """ Test that the convenient method get_version() works. """ runner = test.runner.get_runner() with runner.get_tor_controller() as controller: version = controller.get_version() self.assertTrue(isinstance(version, stem.version.Version)) self.assertEqual(version, test.tor_version())
def test_torrc_arguments_via_stdin(tor_cmd): """ Pass configuration options via stdin. """ if test.tor_version() < stem.version.Requirement.TORRC_VIA_STDIN: skip('(requires )' % stem.version.Requirement.TORRC_VIA_STDIN) with tmp_directory() as data_directory: torrc = BASIC_RELAY_TORRC % data_directory output = run_tor(tor_cmd, '-f', '-', '--dump-config', 'short', stdin = torrc) assert_equal(sorted(torrc.splitlines()), sorted(output.splitlines()))
def test_send_buffered(self): """ Sends multiple requests before receiving back any of the replies. """ runner = test.runner.get_runner() with runner.get_tor_socket() as control_socket: for _ in range(100): control_socket.send('GETINFO version') for _ in range(100): response = control_socket.recv() self.assertTrue( str(response).startswith('version=%s' % test.tor_version())) self.assertTrue(str(response).endswith('\nOK'))
def test_take_ownership_via_pid(tor_cmd): """ Checks that the tor process quits after we do if we set take_ownership. To test this we spawn a process and trick tor into thinking that it is us. """ if not stem.util.system.is_available('sleep'): skip('(sleep unavailable)') elif test.tor_version() < stem.version.Requirement.TAKEOWNERSHIP: skip('(requires %s)' % stem.version.Requirement.TAKEOWNERSHIP) with tmp_directory() as data_directory: sleep_process = subprocess.Popen(['sleep', '60']) tor_process = stem.process.launch_tor_with_config( tor_cmd=tor_cmd, config={ 'SocksPort': random_port(), 'ControlPort': random_port(), 'DataDirectory': data_directory, '__OwningControllerProcess': str(sleep_process.pid), }, completion_percent=0, ) # Kill the sleep command. Tor should quit shortly after. sleep_process.kill() sleep_process.communicate() # tor polls for the process every fifteen seconds so this may take a # while... # # https://trac.torproject.org/projects/tor/ticket/21281 start_time = time.time() while time.time() - start_time < 30: if tor_process.poll() == 0: return # tor exited time.sleep(0.01) raise AssertionError( "tor didn't quit after the process that owned it terminated")
def test_running_file(self): if test.runner.Torrc.PASSWORD in test.runner.get_runner().get_options(): self.skipTest('password auth unsupported') return expected = [ '250-config-file=%s' % test.runner.get_runner().get_torrc_path(), '250 OK', '', '250-version=%s' % test.tor_version(), '250 OK', ] with tempfile.NamedTemporaryFile(prefix = 'test_commands.') as tmp: tmp.write(b'GETINFO config-file\nGETINFO version') tmp.flush() self.assertEqual(expected, _run_prompt('--run', tmp.name))
def test_torrc_arguments_via_stdin(tor_cmd): """ Pass configuration options via stdin. """ if test.tor_version() < stem.version.Requirement.TORRC_VIA_STDIN: skip('(requires %s)' % stem.version.Requirement.TORRC_VIA_STDIN) with tmp_directory() as data_directory: torrc = BASIC_RELAY_TORRC % data_directory output = run_tor(tor_cmd, '-f', '-', '--dump-config', 'short', stdin=torrc) assert_equal(sorted(torrc.splitlines()), sorted(output.splitlines()))
def test_running_file(self): if test.runner.Torrc.PASSWORD in test.runner.get_runner().get_options( ): self.skipTest('password auth unsupported') expected = [ '250-config-file=%s' % test.runner.get_runner().get_torrc_path(), '250 OK', '', '250-version=%s' % test.tor_version(), '250 OK', ] with tempfile.NamedTemporaryFile(prefix='test_commands.') as tmp: tmp.write(b'GETINFO config-file\nGETINFO version') tmp.flush() self.assertEqual(expected, _run_prompt('--run', tmp.name))
def test_take_ownership_via_pid(tor_cmd): """ Checks that the tor process quits after we do if we set take_ownership. To test this we spawn a process and trick tor into thinking that it is us. """ if not stem.util.system.is_available('sleep'): skip('(sleep unavailable)') elif test.tor_version() < stem.version.Requirement.TAKEOWNERSHIP: skip('(requires )' % stem.version.Requirement.TAKEOWNERSHIP) with tmp_directory() as data_directory: sleep_process = subprocess.Popen(['sleep', '60']) tor_process = stem.process.launch_tor_with_config( tor_cmd = tor_cmd, config = { 'SocksPort': random_port(), 'ControlPort': random_port(), 'DataDirectory': data_directory, '__OwningControllerProcess': str(sleep_process.pid), }, completion_percent = 5, ) # Kill the sleep command. Tor should quit shortly after. sleep_process.kill() sleep_process.communicate() # tor polls for the process every fifteen seconds so this may take a # while... # # https://trac.torproject.org/projects/tor/ticket/21281 start_time = time.time() while time.time() - start_time < 30: if tor_process.poll() == 0: return # tor exited time.sleep(0.01) raise AssertionError("tor didn't quit after the process that owned it terminated")
def test_take_ownership_via_controller(tor_cmd): """ Checks that the tor process quits after the controller that owns it connects, then disconnects.. """ if test.tor_version() < stem.version.Requirement.TAKEOWNERSHIP: skip('(requires %s)' % stem.version.Requirement.TAKEOWNERSHIP) with tmp_directory() as data_directory: control_port = random_port() tor_process = stem.process.launch_tor_with_config( tor_cmd=tor_cmd, config={ 'SocksPort': random_port(), 'ControlPort': control_port, 'DataDirectory': data_directory, }, completion_percent=0, take_ownership=True, ) # We're the controlling process. Just need to connect then disconnect. controller = stem.control.Controller.from_port( port=int(control_port)) controller.authenticate() controller.close() # give tor a few seconds to quit start_time = time.time() while time.time() - start_time < 5: if tor_process.poll() == 0: return # tor exited time.sleep(0.01) raise AssertionError( "tor didn't quit after the controller that owned it disconnected" )
def test_launch_tor_with_config_via_stdin(tor_cmd): """ Exercises launch_tor_with_config when we provide our torrc via stdin. """ if test.tor_version() < stem.version.Requirement.TORRC_VIA_STDIN: skip('(requires %s)' % stem.version.Requirement.TORRC_VIA_STDIN) with tmp_directory() as data_directory: control_port = random_port() control_socket, tor_process = None, None try: tor_process = stem.process.launch_tor_with_config( tor_cmd=tor_cmd, config={ 'SocksPort': random_port(), 'ControlPort': control_port, 'DataDirectory': data_directory, }, completion_percent=0) control_socket = stem.socket.ControlPort( port=int(control_port)) stem.connection.authenticate(control_socket) # exercises the socket control_socket.send('GETCONF ControlPort') getconf_response = control_socket.recv() assert_equal('ControlPort=%s' % control_port, str(getconf_response)) finally: if control_socket: control_socket.close() if tor_process: tor_process.kill() tor_process.wait()
def test_take_ownership_via_controller(tor_cmd): """ Checks that the tor process quits after the controller that owns it connects, then disconnects.. """ if test.tor_version() < stem.version.Requirement.TAKEOWNERSHIP: skip('(requires )' % stem.version.Requirement.TAKEOWNERSHIP) with tmp_directory() as data_directory: control_port = random_port() tor_process = stem.process.launch_tor_with_config( tor_cmd = tor_cmd, config = { 'SocksPort': random_port(), 'ControlPort': control_port, 'DataDirectory': data_directory, }, completion_percent = 5, take_ownership = True, ) # We're the controlling process. Just need to connect then disconnect. controller = stem.control.Controller.from_port(port = int(control_port)) controller.authenticate() controller.close() # give tor a few seconds to quit start_time = time.time() while time.time() - start_time < 5: if tor_process.poll() == 0: return # tor exited time.sleep(0.01) raise AssertionError("tor didn't quit after the controller that owned it disconnected")
def test_launch_tor_with_config_via_stdin(tor_cmd): """ Exercises launch_tor_with_config when we provide our torrc via stdin. """ if test.tor_version() < stem.version.Requirement.TORRC_VIA_STDIN: skip('(requires )' % stem.version.Requirement.TORRC_VIA_STDIN) with tmp_directory() as data_directory: control_port = random_port() control_socket, tor_process = None, None try: tor_process = stem.process.launch_tor_with_config( tor_cmd = tor_cmd, config = { 'SocksPort': random_port(), 'ControlPort': control_port, 'DataDirectory': data_directory, }, completion_percent = 5 ) control_socket = stem.socket.ControlPort(port = int(control_port)) stem.connection.authenticate(control_socket) # exercises the socket control_socket.send('GETCONF ControlPort') getconf_response = control_socket.recv() assert_equal('ControlPort=%s' % control_port, str(getconf_response)) finally: if control_socket: control_socket.close() if tor_process: tor_process.kill() tor_process.wait()
def _check_tor_version(tor_path): return str(test.tor_version(tor_path)).split()[0]
def setUp(self): self.cookie_auth_methods = [stem.connection.AuthMethod.COOKIE] if test.tor_version() >= stem.version.Requirement.AUTH_SAFECOOKIE: self.cookie_auth_methods.append(stem.connection.AuthMethod.SAFECOOKIE)