def test_summary_examples(self): # checks the summary() method's pydoc examples policy = ExitPolicy("accept *:80", "accept *:443", "reject *:*") self.assertEquals("accept 80, 443", policy.summary()) policy = ExitPolicy("accept *:443", "reject *:1-1024", "accept *:*") self.assertEquals("reject 1-442, 444-1024", policy.summary())
def test_all_default_policy(self): policy = ExitPolicy(*DEFAULT_POLICY_RULES) for rule in policy: self.assertTrue(rule.is_default()) self.assertTrue(policy.has_default()) self.assertEqual(ExitPolicy(), policy.strip_default())
def test_str(self): # sanity test for our __str__ method policy = ExitPolicy(' accept *:80\n', '\taccept *:443') self.assertEqual('accept *:80, accept *:443', str(policy)) policy = ExitPolicy('reject 0.0.0.0/255.255.255.0:*', 'accept *:*') self.assertEqual('reject 0.0.0.0/24:*, accept *:*', str(policy))
def test_mixed_default_policy(self): policy = ExitPolicy('accept *:80', 'accept 127.0.0.1:1-65533', *DEFAULT_POLICY_RULES) for rule in policy: # only accept-all and reject rules are the default ones self.assertTrue(rule.is_accept != rule.is_default() or (rule.is_accept and rule.is_address_wildcard() and rule.is_port_wildcard())) self.assertEqual(get_config_policy('accept *:80, accept 127.0.0.1:1-65533'), policy.strip_default())
def test_mixed_default_policy(self): policy = ExitPolicy('accept *:80', 'accept 127.0.0.1:1-65533', *DEFAULT_POLICY_RULES) for rule in policy: # only accept-all and reject rules are the default ones self.assertTrue(rule.is_accept != rule.is_default() or (rule.is_accept and rule.is_address_wildcard() and rule.is_port_wildcard())) self.assertEqual(ExitPolicy('accept *:80', 'accept 127.0.0.1:1-65533'), policy.strip_default())
def test_summary_examples(self): # checks the summary() method's pydoc examples policy = ExitPolicy('accept *:80', 'accept *:443', 'reject *:*') self.assertEqual('accept 80, 443', policy.summary()) policy = ExitPolicy('accept *:443', 'reject *:1-1024', 'accept *:*') self.assertEqual('reject 1-442, 444-1024', policy.summary())
def test_example(self): # tests the ExitPolicy and MicroExitPolicy pydoc examples policy = ExitPolicy('accept *:80', 'accept *:443', 'reject *:*') self.assertEqual('accept *:80, accept *:443, reject *:*', str(policy)) self.assertEqual('accept 80, 443', policy.summary()) self.assertTrue(policy.can_exit_to('75.119.206.243', 80)) policy = MicroExitPolicy('accept 80,443') self.assertTrue(policy.can_exit_to('75.119.206.243', 80))
def test_example(self): # tests the ExitPolicy and MicroExitPolicy pydoc examples policy = ExitPolicy("accept *:80", "accept *:443", "reject *:*") self.assertEquals("accept *:80, accept *:443, reject *:*", str(policy)) self.assertEquals("accept 80, 443", policy.summary()) self.assertTrue(policy.can_exit_to("75.119.206.243", 80)) policy = MicroExitPolicy("accept 80,443") self.assertTrue(policy.can_exit_to("75.119.206.243", 80))
def test_iter(self): # sanity test for our __iter__ method rules = [ ExitPolicyRule('accept *:80'), ExitPolicyRule('accept *:443'), ExitPolicyRule('reject *:*'), ] self.assertEqual(rules, list(ExitPolicy(*rules))) self.assertEqual(rules, list(ExitPolicy('accept *:80', 'accept *:443', 'reject *:*')))
def test_can_exit_to(self): # Basic sanity test for our can_exit_to() method. Most of the interesting # use cases (ip masks, wildcards, etc) are covered by the ExitPolicyRule # tests. policy = ExitPolicy('accept *:80', 'accept *:443', 'reject *:*') for index in range(1, 100): ip_addr = '%i.%i.%i.%i' % (index / 2, index / 2, index / 2, index / 2) expected_result = index in (80, 443) self.assertEqual(expected_result, policy.can_exit_to(ip_addr, index)) self.assertEqual(expected_result, policy.can_exit_to(port = index))
def test_all_private_policy(self): for port in ('*', '80', '1-1024'): private_policy = get_config_policy('reject private:%s' % port) for rule in private_policy: self.assertTrue(rule.is_private()) self.assertEqual(ExitPolicy(), private_policy.strip_private()) # though not commonly done, technically private policies can be accept rules too private_policy = get_config_policy('accept private:*') self.assertEqual(ExitPolicy(), private_policy.strip_private())
def test_pickleability(self): """ Checks that we can unpickle ExitPolicy instances. """ policy = ExitPolicy('accept *:80', 'accept *:443', 'reject *:*') self.assertTrue(policy.can_exit_to('74.125.28.106', 80)) encoded_policy = pickle.dumps(policy) restored_policy = pickle.loads(encoded_policy) self.assertEqual(policy, restored_policy) self.assertTrue(restored_policy.is_exiting_allowed()) self.assertTrue(restored_policy.can_exit_to('74.125.28.106', 80))
def test_is_exiting_allowed(self): test_inputs = { (): True, ('accept *:*', ): True, ('reject *:*', ): False, ('accept *:80', 'reject *:*'): True, ('reject *:80', 'accept *:80', 'reject *:*'): False, ('reject *:50-90', 'accept *:80', 'reject *:*'): False, ('reject *:2-65535', 'accept *:80-65535', 'reject *:*'): False, ('reject *:2-65535', 'accept 127.0.0.0:1', 'reject *:*'): True, ('reject 127.0.0.1:*', 'accept *:80', 'reject *:*'): True, } for rules, expected_result in test_inputs.items(): policy = ExitPolicy(*rules) self.assertEqual(expected_result, policy.is_exiting_allowed())
def test_constructor(self): # The ExitPolicy constructor takes a series of string or ExitPolicyRule # entries. Extra whitespace is ignored to make csvs easier to handle. expected_policy = ExitPolicy( ExitPolicyRule('accept *:80'), ExitPolicyRule('accept *:443'), ExitPolicyRule('reject *:*'), ) policy = ExitPolicy('accept *:80', 'accept *:443', 'reject *:*') self.assertEquals(expected_policy, policy) policy = ExitPolicy( *"accept *:80, accept *:443, reject *:*".split(",")) self.assertEquals(expected_policy, policy)
def test_is_exiting_allowed(self): test_inputs = { (): True, ("accept *:*",): True, ("reject *:*",): False, ("accept *:80", "reject *:*"): True, ("reject *:80", "accept *:80", "reject *:*"): False, ("reject *:50-90", "accept *:80", "reject *:*"): False, ("reject *:2-65535", "accept *:80-65535", "reject *:*"): False, ("reject *:2-65535", "accept 127.0.0.0:1", "reject *:*"): True, ("reject 127.0.0.1:*", "accept *:80", "reject *:*"): True, } for rules, expected_result in test_inputs.items(): policy = ExitPolicy(*rules) self.assertEquals(expected_result, policy.is_exiting_allowed())
def test_get_exit_policy(self, get_conf_mock, get_info_mock): """ Exercises the get_exit_policy() method. """ get_conf_mock.side_effect = lambda param, **kwargs: { 'ExitPolicyRejectPrivate': '1', 'ExitPolicy': ['accept *:80, accept *:443', 'accept 43.5.5.5,reject *:22'], }[param] get_info_mock.side_effect = lambda param, default=None: { 'exit-policy/full': 'reject *:25,reject *:119,reject *:135-139,reject *:445,reject *:563,reject *:1214,reject *:4661-4666,reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*', }[param] expected = ExitPolicy( 'reject *:25', 'reject *:119', 'reject *:135-139', 'reject *:445', 'reject *:563', 'reject *:1214', 'reject *:4661-4666', 'reject *:6346-6429', 'reject *:6699', 'reject *:6881-6999', 'accept *:*', ) self.assertEqual(expected, self.controller.get_exit_policy())
def test_get_exit_policy(self, get_info_mock): """ Exercises the get_exit_policy() method. """ get_info_mock.side_effect = lambda param, default=None: { 'exit-policy/full': 'reject *:25,reject *:119,reject *:135-139,reject *:445,reject *:563,reject *:1214,reject *:4661-4666,reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*', }[param] expected = ExitPolicy( 'reject *:25', 'reject *:119', 'reject *:135-139', 'reject *:445', 'reject *:563', 'reject *:1214', 'reject *:4661-4666', 'reject *:6346-6429', 'reject *:6699', 'reject *:6881-6999', 'accept *:*', ) self.assertEqual(str(expected), str(self.controller.get_exit_policy()))
def test_mirror_mirror_on_the_wall_4(self, get_desc_mock, stdout_mock): get_desc_mock.return_value = iter([RelayDescriptor.create({ 'router': 'caerSidi 71.35.133.197 9001 0 0', 'fingerprint': '2C3C 4662 5698 B6D6 7DF3 2BC1 918A D3EE 1F99 06B1', }, exit_policy = ExitPolicy('accept *:*'), validate = False)]) exec_documentation_example('collector_reading.py') self.assertEqual(' caerSidi (2C3C46625698B6D67DF32BC1918AD3EE1F9906B1)\n', stdout_mock.getvalue())
def test_can_exit_to_strictness(self): # Check our 'strict' argument. policy = ExitPolicy('reject 1.0.0.0/8:80', 'accept *:*') self.assertEqual(False, policy.can_exit_to(None, 80, strict = True)) # can't exit to *all* instances of port 80 self.assertEqual(True, policy.can_exit_to(None, 80, strict = False)) # can exit to *an* instance of port 80 policy = ExitPolicy('accept 1.0.0.0/8:80', 'reject *:*') self.assertEqual(False, policy.can_exit_to(None, 80, strict = True)) # can't exit to *all* instances of port 80 self.assertEqual(True, policy.can_exit_to(None, 80, strict = False)) # can exit to *an* instance of port 80
def test_get_exit_policy(self): """ Exercises the get_exit_policy() method. """ mocking.mock_method( Controller, "get_conf", mocking.return_for_args( { ("ExitPolicyRejectPrivate", ): "1", ("ExitPolicy", "multiple=True"): [ "accept *:80, accept *:443", "accept 43.5.5.5,reject *:22" ] }, is_method=True)) mocking.mock_method( Controller, "get_info", mocking.return_for_args( { ("address", None): "123.45.67.89", ("exit-policy/default", ): "reject *:25,reject *:119,reject *:135-139,reject *:445,reject *:563,reject *:1214,reject *:4661-4666,reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*" }, is_method=True)) expected = ExitPolicy( 'reject 0.0.0.0/8:*', # private entries 'reject 169.254.0.0/16:*', 'reject 127.0.0.0/8:*', 'reject 192.168.0.0/16:*', 'reject 10.0.0.0/8:*', 'reject 172.16.0.0/12:*', 'reject 123.45.67.89:*', # relay's public address 'accept *:80', # finally we get to our ExitPolicy 'accept *:443', 'accept 43.5.5.5:*', 'reject *:22', 'reject *:25', # default policy 'reject *:119', 'reject *:135-139', 'reject *:445', 'reject *:563', 'reject *:1214', 'reject *:4661-4666', 'reject *:6346-6429', 'reject *:6699', 'reject *:6881-6999', 'accept *:*', ) self.assertEqual(expected, self.controller.get_exit_policy())
def test_get_exit_policy_if_not_relaying(self, get_conf_mock, get_info_mock): # If tor lacks an ORPort, resolved extrnal address, hasn't finished making # our server descriptor (ie. tor just started), etc 'GETINFO # exit-policy/full' will fail. get_conf_mock.side_effect = lambda param, **kwargs: { 'ExitRelay': '1', 'ExitPolicyRejectPrivate': '1', 'ExitPolicy': ['accept *:80, accept *:443', 'accept 43.5.5.5,reject *:22'], }[param] expected = ExitPolicy( 'reject 0.0.0.0/8:*', 'reject 169.254.0.0/16:*', 'reject 127.0.0.0/8:*', 'reject 192.168.0.0/16:*', 'reject 10.0.0.0/8:*', 'reject 172.16.0.0/12:*', 'reject 1.2.3.4:*', 'accept *:80', 'accept *:443', 'accept 43.5.5.5:*', 'reject *:22', ) # Unfortunate it's a bit tricky to have a mock that raises exceptions in # response to some arguments, and returns a response for others. As such # mapping it to the following function. exit_policy_exception = None def getinfo_response(param, default=None): if param == 'address': return '1.2.3.4' elif param == 'exit-policy/default': return '' elif param == 'exit-policy/full' and exit_policy_exception: raise exit_policy_exception else: raise ValueError("Unmocked request for 'GETINFO %s'" % param) get_info_mock.side_effect = getinfo_response exit_policy_exception = stem.OperationFailed( '552', 'Not running in server mode') self.assertEqual(str(expected), str(self.controller.get_exit_policy())) exit_policy_exception = stem.OperationFailed( '551', 'Descriptor still rebuilding - not ready yet') self.assertEqual(str(expected), str(self.controller.get_exit_policy()))
def test_constructor(self): # The ExitPolicy constructor takes a series of string or ExitPolicyRule # entries. Extra whitespace is ignored to make csvs easier to handle. expected_policy = ExitPolicy( ExitPolicyRule('accept *:80'), ExitPolicyRule('accept *:443'), ExitPolicyRule('reject *:*'), ) policy = ExitPolicy('accept *:80', 'accept *:443', 'reject *:*') self.assertEqual(expected_policy, policy) policy = ExitPolicy( *'accept *:80, accept *:443, reject *:*'.split(',')) self.assertEqual(expected_policy, policy) # checks that we truncate after getting a catch-all policy policy = ExitPolicy( *'accept *:80, accept *:443, reject *:*, accept *:20-50'.split( ',')) self.assertEqual(expected_policy, policy) # checks that we compress redundant policies policy = ExitPolicy( *'reject *:80, reject *:443, reject *:*'.split(',')) self.assertEqual(ExitPolicy('reject *:*'), policy)
def test_relay_connections(self, connect_mock, get_connections_mock): import relay_connections with patch('sys.stdout', new_callable=io.StringIO) as stdout_mock: connect_mock.return_value = None relay_connections.main(['--help']) self.assertEqual(EXPECTED_RELAY_CONNECTIONS_HELP, stdout_mock.getvalue()) with patch('sys.stdout', new_callable=io.StringIO) as stdout_mock: consensus_desc = RouterStatusEntryV2.create({ 'r': 'caerSidi p1aag7VwarGxqctS7/fS0y5FU+s oQZFLYe9e4A7bOkWKR7TaNxb0JE 2012-08-06 11:19:31 71.35.150.29 9001 0', 's': 'Fast Stable', }) controller = Mock() controller.get_pid.return_value = 123 controller.get_version.return_value = stem.version.Version( '1.2.3.4') controller.get_exit_policy.return_value = ExitPolicy('reject *:*') controller.get_network_status.return_value = consensus_desc controller.get_network_statuses.return_value = [consensus_desc] controller.get_ports.side_effect = lambda port_type, default_val: { Listener.OR: [4369], Listener.DIR: [443], Listener.CONTROL: [9100], }.get(port_type, default_val) connect_mock.return_value = controller get_connections_mock.return_value = [ Connection('17.17.17.17', 4369, '34.34.34.34', 8738, 'tcp', False), Connection('18.18.18.18', 443, '35.35.35.35', 4281, 'tcp', False), Connection('19.19.19.19', 443, '36.36.36.36', 2814, 'tcp', False), Connection('20.20.20.20', 9100, '37.37.37.37', 2814, 'tcp', False), Connection('21.21.21.21', 80, '38.38.38.38', 8142, 'tcp', False), ] relay_connections.main([]) self.assertEqual(EXPECTED_RELAY_CONNECTIONS, stdout_mock.getvalue())
def test_collector_reading(self, stdout_mock, server_desc_mock): server_desc_mock.return_value = [ RelayDescriptor.create( { 'router': 'caerSidi 71.35.133.197 9001 0 0', 'fingerprint': '4F0C 867D F0EF 6816 0568 C826 838F 482C EA7C FE44', }, exit_policy=ExitPolicy('accept *:*')), ] import collector_reading self.assertEqual(EXPECTED_COLLECTOR_READING, stdout_mock.getvalue())
def test_non_private_non_default_policy(self): policy = ExitPolicy('reject *:80-65535', 'accept *:1-65533', 'reject *:*') for rule in policy: self.assertFalse(rule.is_private()) self.assertFalse(rule.is_default()) self.assertFalse(policy.has_private()) self.assertFalse(policy.has_default()) self.assertEqual(policy, policy.strip_private()) self.assertEqual(policy, policy.strip_default())
def test_get_exit_policy(self): """ Sanity test for get_exit_policy(). We have the default policy (no ExitPolicy set) which is a little... long due to the boilerplate. """ if test.runner.require_control(self): return expected = ExitPolicy( 'reject 0.0.0.0/8:*', 'reject 169.254.0.0/16:*', 'reject 127.0.0.0/8:*', 'reject 192.168.0.0/16:*', 'reject 10.0.0.0/8:*', 'reject 172.16.0.0/12:*', # this is where 'reject [public_addr]:*' may or may not be 'reject *:25', 'reject *:119', 'reject *:135-139', 'reject *:445', 'reject *:563', 'reject *:1214', 'reject *:4661-4666', 'reject *:6346-6429', 'reject *:6699', 'reject *:6881-6999', 'accept *:*', ) runner = test.runner.get_runner() with runner.get_tor_controller() as controller: # We can't simply compare the policies because the tor policy may or may # not have a reject entry for our public address. Hence, stripping it # from the policy's string, then comparing those. policy_str = str(controller.get_exit_policy()) public_addr_start = policy_str.find('reject 172.16.0.0/12:*') + 22 public_addr_end = policy_str.find(', reject *:25') policy_str = policy_str[:public_addr_start] + policy_str[ public_addr_end:] self.assertEqual(str(expected), policy_str)
def test_get_exit_policy(self, get_conf_mock, get_info_mock): """ Exercises the get_exit_policy() method. """ get_conf_mock.side_effect = lambda param, **kwargs: { 'ExitPolicyRejectPrivate': '1', 'ExitPolicy': ['accept *:80, accept *:443', 'accept 43.5.5.5,reject *:22'], }[param] get_info_mock.side_effect = lambda param, default=None: { 'address': '123.45.67.89', 'exit-policy/default': 'reject *:25,reject *:119,reject *:135-139,reject *:445,reject *:563,reject *:1214,reject *:4661-4666,reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*', }[param] expected = ExitPolicy( 'reject 0.0.0.0/8:*', # private entries 'reject 169.254.0.0/16:*', 'reject 127.0.0.0/8:*', 'reject 192.168.0.0/16:*', 'reject 10.0.0.0/8:*', 'reject 172.16.0.0/12:*', 'reject 123.45.67.89:*', # relay's public address 'accept *:80', # finally we get to our ExitPolicy 'accept *:443', 'accept 43.5.5.5:*', 'reject *:22', 'reject *:25', # default policy 'reject *:119', 'reject *:135-139', 'reject *:445', 'reject *:563', 'reject *:1214', 'reject *:4661-4666', 'reject *:6346-6429', 'reject *:6699', 'reject *:6881-6999', 'accept *:*', ) self.assertEqual(expected, self.controller.get_exit_policy())
def add_adv_middles(self, num_adv_guards, num_adv_exits, num_adv_middles, bandwidth): """"Adds adv middle into self.add_relays and self.add_descriptors.""" for i in xrange(num_adv_middles): # create consensus num_str = str(i+1) fingerprint = 'F0' * (20-len(num_str)) + num_str nickname = 'BadGuyMiddle' + num_str flags = [Flag.FAST, Flag.RUNNING, Flag.STABLE, Flag.VALID] self.adv_relays[fingerprint] = pathsim.RouterStatusEntry(fingerprint, nickname, flags, bandwidth) # create descriptor hibernating = False family = {} address = '10.'+str(num_adv_guards+num_adv_exits+i+1)+'.0.0' # avoid /16 conflicts exit_policy = ExitPolicy('reject *:*') ntor_onion_key = num_str # indicate ntor support w/ val != None self.adv_descriptors[fingerprint] = pathsim.ServerDescriptor(fingerprint, hibernating, nickname, family, address, exit_policy, ntor_onion_key)
def test_get_config_policy(self): test_inputs = { '': ExitPolicy(), 'reject *': ExitPolicy('reject *:*'), 'reject *:*': ExitPolicy('reject *:*'), 'reject private': ExitPolicy( 'reject 0.0.0.0/8:*', 'reject 169.254.0.0/16:*', 'reject 127.0.0.0/8:*', 'reject 192.168.0.0/16:*', 'reject 10.0.0.0/8:*', 'reject 172.16.0.0/12:*', 'reject 12.34.56.78:*', ), 'accept *:80, reject *': ExitPolicy( 'accept *:80', 'reject *:*', ), ' accept *:80, reject * ': ExitPolicy( 'accept *:80', 'reject *:*', ), } for test_input, expected in test_inputs.items(): self.assertEqual(expected, get_config_policy(test_input, '12.34.56.78')) test_inputs = ( 'blarg', 'accept *:*:*', 'acceptt *:80', 'accept 257.0.0.1:80', 'accept *:999999', ) for test_input in test_inputs: self.assertRaises(ValueError, get_config_policy, test_input)
def test_get_config_policy(self): test_inputs = { "": ExitPolicy(), "reject *": ExitPolicy('reject *:*'), "reject *:*": ExitPolicy('reject *:*'), "reject private": ExitPolicy( 'reject 0.0.0.0/8:*', 'reject 169.254.0.0/16:*', 'reject 127.0.0.0/8:*', 'reject 192.168.0.0/16:*', 'reject 10.0.0.0/8:*', 'reject 172.16.0.0/12:*', ), "accept *:80, reject *": ExitPolicy( 'accept *:80', 'reject *:*', ), " accept *:80, reject * ": ExitPolicy( 'accept *:80', 'reject *:*', ), } for test_input, expected in test_inputs.items(): self.assertEqual(expected, get_config_policy(test_input)) test_inputs = ( "blarg", "accept *:*:*", "acceptt *:80", "accept 257.0.0.1:80", "accept *:999999", ) for test_input in test_inputs: self.assertRaises(ValueError, get_config_policy, test_input)
def test_summary_large_ranges(self): # checks the summary() method when the policy includes very large port ranges policy = ExitPolicy('reject *:80-65535', 'accept *:1-65533', 'reject *:*') self.assertEqual('accept 1-79', policy.summary())
def test_set_default_allowed(self): policy = ExitPolicy('reject *:80', 'accept *:443') # our default for being allowed defaults to True self.assertFalse(policy.can_exit_to("75.119.206.243", 80)) self.assertTrue(policy.can_exit_to("75.119.206.243", 443)) self.assertTrue(policy.can_exit_to("75.119.206.243", 999)) policy._set_default_allowed(False) self.assertFalse(policy.can_exit_to("75.119.206.243", 80)) self.assertTrue(policy.can_exit_to("75.119.206.243", 443)) self.assertFalse(policy.can_exit_to("75.119.206.243", 999)) # Our is_exiting_allowed() is also influcenced by this flag if we lack any # 'accept' rules. policy = ExitPolicy() self.assertTrue(policy.is_exiting_allowed()) policy._set_default_allowed(False) self.assertFalse(policy.is_exiting_allowed())
def test_summary_large_ranges(self): # checks the summary() method when the policy includes very large port ranges policy = ExitPolicy("reject *:80-65535", "accept *:1-65533", "reject *:*") self.assertEquals("accept 1-79", policy.summary())
def test_set_default_allowed(self): policy = ExitPolicy("reject *:80", "accept *:443") # our default for being allowed defaults to True self.assertFalse(policy.can_exit_to("75.119.206.243", 80)) self.assertTrue(policy.can_exit_to("75.119.206.243", 443)) self.assertTrue(policy.can_exit_to("75.119.206.243", 999)) policy._set_default_allowed(False) self.assertFalse(policy.can_exit_to("75.119.206.243", 80)) self.assertTrue(policy.can_exit_to("75.119.206.243", 443)) self.assertFalse(policy.can_exit_to("75.119.206.243", 999)) # Our is_exiting_allowed() is also influcenced by this flag if we lack any # 'accept' rules. policy = ExitPolicy() self.assertTrue(policy.is_exiting_allowed()) policy._set_default_allowed(False) self.assertFalse(policy.is_exiting_allowed())