def test_get_connections(self): """ Checks for our control port in the stem.util.proc.get_connections output if we have one. """ runner = test.runner.get_runner() if not proc.is_available(): test.runner.skip(self, "(proc unavailable)") return elif not test.runner.Torrc.PORT in runner.get_options(): test.runner.skip(self, "(no control port)") return elif not test.runner.get_runner().is_ptraceable(): test.runner.skip(self, "(DisableDebuggerAttachment is set)") return # making a controller connection so that we have something to query for with runner.get_tor_socket(): tor_pid = test.runner.get_runner().get_pid() for conn in proc.get_connections(tor_pid): if ("127.0.0.1", test.runner.CONTROL_PORT) == conn[:2]: return self.fail()
def test_connections(self): """ Checks for our control port in the stem.util.proc.connections output if we have one. """ runner = test.runner.get_runner() if not proc.is_available(): test.runner.skip(self, '(proc unavailable)') return elif test.runner.Torrc.PORT not in runner.get_options(): test.runner.skip(self, '(no control port)') return elif not test.runner.get_runner().is_ptraceable(): test.runner.skip(self, '(DisableDebuggerAttachment is set)') return elif not os.access('/proc/net/tcp', os.R_OK) or not os.access('/proc/net/udp', os.R_OK): test.runner.skip(self, '(proc lacks read permissions)') return # making a controller connection so that we have something to query for with runner.get_tor_socket(): tor_pid = test.runner.get_runner().get_pid() for conn in proc.connections(tor_pid): if ('127.0.0.1', test.runner.CONTROL_PORT) == conn[:2]: return self.fail()
async def test_wrong_password_with_controller(self): """ We ran into a race condition where providing the wrong password to the Controller caused inconsistent responses. """ runner = test.runner.get_runner() if test.runner.Torrc.PASSWORD not in runner.get_options( ) or test.runner.Torrc.COOKIE in runner.get_options(): self.skipTest('(requires only password auth)') for i in range(10): async with await runner.get_tor_controller(False) as controller: with self.assertRaises(stem.connection.IncorrectPassword): await controller.authenticate('wrong_password')
def test_authenticate_general_password(self): """ Tests the authenticate function's password argument. """ if test.runner.require_control(self): return # this is a much better test if we're just using password auth, since # authenticate will work reguardless if there's something else to # authenticate with runner = test.runner.get_runner() tor_options = runner.get_options() is_password_only = test.runner.Torrc.PASSWORD in tor_options and not test.runner.Torrc.COOKIE in tor_options # tests without a password with runner.get_tor_socket(False) as control_socket: if is_password_only: self.assertRaises(stem.connection.MissingPassword, stem.connection.authenticate, control_socket) else: stem.connection.authenticate(control_socket, chroot_path = runner.get_chroot()) test.runner.exercise_controller(self, control_socket) # tests with the incorrect password with runner.get_tor_socket(False) as control_socket: if is_password_only: self.assertRaises(stem.connection.IncorrectPassword, stem.connection.authenticate, control_socket, "blarg") else: stem.connection.authenticate(control_socket, "blarg", runner.get_chroot()) test.runner.exercise_controller(self, control_socket) # tests with the right password with runner.get_tor_socket(False) as control_socket: stem.connection.authenticate(control_socket, test.runner.CONTROL_PASSWORD, runner.get_chroot()) test.runner.exercise_controller(self, control_socket)
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 runner.get_tor_version( ).meets_requirements(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_resolver(self, resolver): runner = test.runner.get_runner() if test.runner.Torrc.PORT not in runner.get_options(): self.skipTest('(no control port)') return elif resolver not in system_resolvers(): self.skipTest('(resolver unavailable on this platform)') return with runner.get_tor_socket(): connections = get_connections(resolver, process_pid=runner.get_pid()) for conn in connections: if conn.local_address == '127.0.0.1' and conn.local_port == test.runner.CONTROL_PORT: return resolver_command = RESOLVER_COMMAND[resolver].format( pid=runner.get_pid()) resolver_output = stem.util.system.call(resolver_command) self.fail( 'Unable to find our controller connection with %s (%s). Connections found were...\n\n%s\n\nCommand output was...\n\n%s' % (resolver, resolver_command, '\n'.join(map( str, connections)), resolver_output))
def test_get_listeners(self): """ Test Controller.get_listeners against a running tor instance. """ if test.runner.require_control(self): return runner = test.runner.get_runner() with runner.get_tor_controller() as controller: self.assertEqual([], controller.get_listeners(Listener.OR)) self.assertEqual([], controller.get_listeners(Listener.DIR)) self.assertEqual([('127.0.0.1', test.runner.SOCKS_PORT)], controller.get_listeners(Listener.SOCKS)) self.assertEqual([], controller.get_listeners(Listener.TRANS)) self.assertEqual([], controller.get_listeners(Listener.NATD)) self.assertEqual([], controller.get_listeners(Listener.DNS)) if test.runner.Torrc.PORT in runner.get_options(): self.assertEqual([('127.0.0.1', test.runner.CONTROL_PORT)], controller.get_listeners(Listener.CONTROL)) else: self.assertEqual([], controller.get_listeners(Listener.CONTROL))
def test_authenticate_general_cookie(self): """ Tests the authenticate function with only cookie authentication methods. This manipulates our PROTOCOLINFO response to test each method individually. """ if test.runner.require_control(self): return runner = test.runner.get_runner() tor_options = runner.get_options() is_cookie_only = test.runner.Torrc.COOKIE in tor_options and not test.runner.Torrc.PASSWORD in tor_options # test both cookie authentication mechanisms with runner.get_tor_socket(False) as control_socket: if is_cookie_only: for method in (stem.connection.AuthMethod.COOKIE, stem.connection.AuthMethod.SAFECOOKIE): protocolinfo_response = stem.connection.get_protocolinfo(control_socket) if method in protocolinfo_response.auth_methods: # narrow to *only* use cookie auth or safecooke, so we exercise # both independently protocolinfo_response.auth_methods = (method, ) stem.connection.authenticate(control_socket, chroot_path = runner.get_chroot(), protocolinfo_response = protocolinfo_response)
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 runner.get_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 test_connections(self): """ Checks for our control port in the stem.util.proc.connections output if we have one. """ runner = test.runner.get_runner() if test.runner.Torrc.PORT not in runner.get_options(): self.skiTestp('(no control port)') return elif not os.access('/proc/net/tcp', os.R_OK) or not os.access( '/proc/net/udp', os.R_OK): self.skipTest('(proc lacks read permissions)') return # making a controller connection so that we have something to query for with runner.get_tor_socket(): tor_pid = test.runner.get_runner().get_pid() for conn in proc.connections(tor_pid): if ('127.0.0.1', test.runner.CONTROL_PORT) == conn[:2]: return self.fail()
def test_authenticate_general_example(self): """ Tests the authenticate function with something like its pydoc example. """ runner = test.runner.get_runner() tor_options = runner.get_options() try: control_socket = stem.socket.ControlPort(port = test.runner.CONTROL_PORT) except stem.SocketError: # assert that we didn't have a socket to connect to self.assertFalse(test.runner.Torrc.PORT in tor_options) return try: # this authenticate call should work for everything but password-only auth stem.connection.authenticate(control_socket, chroot_path = runner.get_chroot()) test.runner.exercise_controller(self, control_socket) except stem.connection.IncorrectSocketType: self.fail() except stem.connection.MissingPassword: self.assertTrue(test.runner.Torrc.PASSWORD in tor_options) controller_password = test.runner.CONTROL_PASSWORD try: stem.connection.authenticate_password(control_socket, controller_password) test.runner.exercise_controller(self, control_socket) except stem.connection.PasswordAuthFailed: self.fail() except stem.connection.AuthenticationFailure: self.fail() finally: control_socket.close()
def test_authenticate_general_password(self): """ Tests the authenticate function's password argument. """ # this is a much better test if we're just using password auth, since # authenticate will work reguardless if there's something else to # authenticate with runner = test.runner.get_runner() tor_options = runner.get_options() is_password_only = test.runner.Torrc.PASSWORD in tor_options and test.runner.Torrc.COOKIE not in tor_options # tests without a password with runner.get_tor_socket(False) as control_socket: if is_password_only: self.assertRaises(stem.connection.MissingPassword, stem.connection.authenticate, control_socket) else: stem.connection.authenticate(control_socket, chroot_path = runner.get_chroot()) test.runner.exercise_controller(self, control_socket) # tests with the incorrect password with runner.get_tor_socket(False) as control_socket: if is_password_only: self.assertRaises(stem.connection.IncorrectPassword, stem.connection.authenticate, control_socket, 'blarg') else: stem.connection.authenticate(control_socket, 'blarg', runner.get_chroot()) test.runner.exercise_controller(self, control_socket) # tests with the right password with runner.get_tor_socket(False) as control_socket: stem.connection.authenticate(control_socket, test.runner.CONTROL_PASSWORD, runner.get_chroot()) test.runner.exercise_controller(self, control_socket)
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) 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 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_protocolinfo(self): """ Test that the convenient method protocolinfo() works. """ if test.runner.require_control(self): return 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() tor_version = runner.get_tor_version() auth_methods = [] if test.runner.Torrc.COOKIE in tor_options: auth_methods.append(stem.response.protocolinfo.AuthMethod.COOKIE) if 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 test_authenticate_general_cookie(self): """ Tests the authenticate function with only cookie authentication methods. This manipulates our PROTOCOLINFO response to test each method individually. """ if test.runner.require_control(self): return runner = test.runner.get_runner() tor_options = runner.get_options() is_cookie_only = test.runner.Torrc.COOKIE in tor_options and not test.runner.Torrc.PASSWORD in tor_options # test both cookie authentication mechanisms with runner.get_tor_socket(False) as control_socket: if is_cookie_only: for method in (stem.connection.AuthMethod.COOKIE, stem.connection.AuthMethod.SAFECOOKIE): protocolinfo_response = stem.connection.get_protocolinfo( control_socket) if method in protocolinfo_response.auth_methods: # narrow to *only* use cookie auth or safecooke, so we exercise # both independently protocolinfo_response.auth_methods = (method, ) stem.connection.authenticate( control_socket, chroot_path=runner.get_chroot(), protocolinfo_response=protocolinfo_response)
def test_wrong_password_with_controller(self): """ We ran into a race condition where providing the wrong password to the Controller caused inconsistent responses. Checking for that... https://trac.torproject.org/projects/tor/ticket/22679 """ runner = test.runner.get_runner() if test.runner.Torrc.PASSWORD not in runner.get_options( ) or test.runner.Torrc.COOKIE in runner.get_options(): self.skipTest('(requires only password auth)') for i in range(10): with runner.get_tor_controller(False) as controller: self.assertRaises(stem.connection.IncorrectPassword, controller.authenticate, 'wrong_password')
def test_wrong_password_with_controller(self): """ We ran into a race condition where providing the wrong password to the Controller caused inconsistent responses. Checking for that... https://trac.torproject.org/projects/tor/ticket/22679 """ runner = test.runner.get_runner() if test.runner.Torrc.PASSWORD not in runner.get_options() or test.runner.Torrc.COOKIE in runner.get_options(): self.skipTest('(requires only password auth)') return for i in range(10): with runner.get_tor_controller(False) as controller: self.assertRaises(stem.connection.IncorrectPassword, controller.authenticate, 'wrong_password')
def test_connect_socket_file(self): """ Basic sanity checks for the connect_socket_file function. """ runner = test.runner.get_runner() control_socket = stem.connection.connect_socket_file( socket_path = test.runner.CONTROL_SOCKET_PATH, password = test.runner.CONTROL_PASSWORD, chroot_path = runner.get_chroot(), controller = None) if test.runner.Torrc.SOCKET in runner.get_options(): test.runner.exercise_controller(self, control_socket) control_socket.close() else: self.assertEquals(control_socket, None)
def check_resolver(self, resolver): runner = test.runner.get_runner() if test.runner.Torrc.PORT not in runner.get_options(): self.skipTest('(no control port)') return elif resolver not in system_resolvers(): self.skipTest('(resolver unavailable on this platform)') return with runner.get_tor_socket(): connections = get_connections(resolver, process_pid = runner.get_pid()) for conn in connections: if conn.local_address == '127.0.0.1' and conn.local_port == test.runner.CONTROL_PORT: return self.fail('Unable to find localhost connection with %s:\n%s' % (resolver, '\n'.join(connections)))
def test_connect_socket_file(self): """ Basic sanity checks for the connect_socket_file function. """ runner = test.runner.get_runner() control_socket = stem.connection.connect_socket_file( path=test.runner.CONTROL_SOCKET_PATH, password=test.runner.CONTROL_PASSWORD, chroot_path=runner.get_chroot(), controller=None) if test.runner.Torrc.SOCKET in runner.get_options(): test.runner.exercise_controller(self, control_socket) control_socket.close() else: self.assertEqual(control_socket, None)
def test_connect_port(self, stdout_mock): """ Basic sanity checks for the connect_port function. """ runner = test.runner.get_runner() control_socket = stem.connection.connect_port( port=test.runner.CONTROL_PORT, password=test.runner.CONTROL_PASSWORD, chroot_path=runner.get_chroot(), controller=None) if test.runner.Torrc.PORT in runner.get_options(): test.runner.exercise_controller(self, control_socket) control_socket.close() self.assertEqual('', stdout_mock.getvalue()) else: self.assertEqual(control_socket, None)
def test_get_listeners(self): """ Test Controller.get_listeners against a running tor instance. """ runner = test.runner.get_runner() with runner.get_tor_controller() as controller: self.assertEqual([], controller.get_listeners(Listener.OR)) self.assertEqual([], controller.get_listeners(Listener.DIR)) self.assertEqual([('127.0.0.1', test.runner.SOCKS_PORT)], controller.get_listeners(Listener.SOCKS)) self.assertEqual([], controller.get_listeners(Listener.TRANS)) self.assertEqual([], controller.get_listeners(Listener.NATD)) self.assertEqual([], controller.get_listeners(Listener.DNS)) if test.runner.Torrc.PORT in runner.get_options(): self.assertEqual([('127.0.0.1', test.runner.CONTROL_PORT)], controller.get_listeners(Listener.CONTROL)) else: self.assertEqual([], controller.get_listeners(Listener.CONTROL))
def test_get_connections(self): runner = test.runner.get_runner() if not test.runner.Torrc.PORT in runner.get_options(): test.runner.skip(self, '(no control port)') return elif not test.runner.get_runner().is_ptraceable(): test.runner.skip(self, '(DisableDebuggerAttachment is set)') return for resolver in get_system_resolvers(): with runner.get_tor_socket(): tor_pid = test.runner.get_runner().get_pid() connections = get_connections(resolver, process_pid = tor_pid) for conn in connections: if conn.local_address == '127.0.0.1' and conn.local_port == test.runner.CONTROL_PORT: return self.fail('Unable to find localhost connection with %s:\n%s' % (resolver, '\n'.join(connections)))
def check_resolver(self, resolver): runner = test.runner.get_runner() if test.runner.Torrc.PORT not in runner.get_options(): self.skipTest('(no control port)') return elif resolver not in system_resolvers(): self.skipTest('(resolver unavailable on this platform)') return with runner.get_tor_socket(): connections = get_connections(resolver, process_pid=runner.get_pid()) for conn in connections: if conn.local_address == '127.0.0.1' and conn.local_port == test.runner.CONTROL_PORT: return self.fail('Unable to find localhost connection with %s:\n%s' % (resolver, '\n'.join(connections)))
def test_connect_port(self): """ Basic sanity checks for the connect_port function. """ if test.runner.require_control(self): return runner = test.runner.get_runner() control_socket = stem.connection.connect_port( control_port = test.runner.CONTROL_PORT, password = test.runner.CONTROL_PASSWORD, chroot_path = runner.get_chroot(), controller = None) if test.runner.Torrc.PORT in runner.get_options(): test.runner.exercise_controller(self, control_socket) control_socket.close() else: self.assertEquals(control_socket, None)
def test_connect_port(self): """ Basic sanity checks for the connect_port function. """ if test.runner.require_control(self): return runner = test.runner.get_runner() control_socket = stem.connection.connect_port( control_port=test.runner.CONTROL_PORT, password=test.runner.CONTROL_PASSWORD, chroot_path=runner.get_chroot(), controller=None) if test.runner.Torrc.PORT in runner.get_options(): test.runner.exercise_controller(self, control_socket) control_socket.close() else: self.assertEquals(control_socket, None)