[tor-commits] [stem/master] Better handling for default exit policy suffix

atagar at torproject.org atagar at torproject.org
Sun Sep 7 19:31:10 UTC 2014


commit e0aeefb8c721b285fa23e1097cf8be45b86aa538
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Sep 7 11:50:39 2014 -0700

    Better handling for default exit policy suffix
    
    Methods similar to the private entries to better handle the policy entries tor
    adds to the suffix by default if we lack an accept-all or reject-all rule.
---
 stem/exit_policy.py             |   66 ++++++++++++++++++++++++++++++++++++++-
 test/unit/exit_policy/policy.py |   33 +++++++++++++++++---
 2 files changed, 93 insertions(+), 6 deletions(-)

diff --git a/stem/exit_policy.py b/stem/exit_policy.py
index 1f72b60..06f4d83 100644
--- a/stem/exit_policy.py
+++ b/stem/exit_policy.py
@@ -30,7 +30,9 @@ exiting to a destination is permissible or not. For instance...
     |- can_exit_to - check if exiting to this destination is allowed or not
     |- is_exiting_allowed - check if any exiting is allowed
     |- summary - provides a short label, similar to a microdescriptor
+    |- is_default - checks if policy ends with the defaultly appended suffix
     |- strip_private - provides a copy of the policy without 'private' entries
+    |- strip_default - provides a copy of the policy without the default suffix
     |- __str__  - string representation
     +- __iter__ - ExitPolicyRule entries that this contains
 
@@ -44,6 +46,7 @@ exiting to a destination is permissible or not. For instance...
     |- get_mask - provides the address representation of our mask
     |- get_masked_bits - provides the bit representation of our mask
     |- is_private - flag indicating if this was expanded from a 'private' keyword
+    |- is_default - flag indicating if this was part of the default end of a policy
     +- __str__ - string representation for this rule
 
   get_config_policy - provides the ExitPolicy based on torrc rules
@@ -200,6 +203,19 @@ def _flag_private_rules(rules):
         rule._is_private = True
 
 
+def _flag_default_rules(rules):
+  """
+  Determine if part of our policy ends with the defaultly appended suffix.
+  """
+
+  if len(rules) >= len(DEFAULT_POLICY_RULES):
+    rules_suffix = tuple(rules[-len(DEFAULT_POLICY_RULES):])
+
+    if rules_suffix == DEFAULT_POLICY_RULES:
+      for rule in rules_suffix:
+        rule._is_default_suffix = True
+
+
 class ExitPolicy(object):
   """
   Policy for the destinations that a relay allows or denies exiting to. This
@@ -365,6 +381,19 @@ class ExitPolicy(object):
 
     return (label_prefix + ', '.join(display_ranges)).strip()
 
+  def is_default(self):
+    """
+    Checks if we have the default policy suffix.
+
+    :returns: **True** if we have the default policy suffix, **False** otherwise
+    """
+
+    for rule in self._get_rules():
+      if rule.is_default():
+        return True
+
+    return False
+
   def strip_private(self):
     """
     Provides a copy of this policy without 'private' policy entries.
@@ -374,6 +403,15 @@ class ExitPolicy(object):
 
     return ExitPolicy(*[rule for rule in self._get_rules() if not rule.is_private()])
 
+  def strip_default(self):
+    """
+    Provides a copy of this policy without the default policy suffix.
+
+    :returns: **ExitPolicy** without default rules
+    """
+
+    return ExitPolicy(*[rule for rule in self._get_rules() if not rule.is_default()])
+
   def _get_rules(self):
     if self._rules is None:
       rules = []
@@ -421,12 +459,16 @@ class ExitPolicy(object):
           rules = [ExitPolicyRule('reject *:*')]
 
       _flag_private_rules(rules)
+      _flag_default_rules(rules)
 
       self._rules = rules
       self._input_rules = None
 
     return self._rules
 
+  def __len__(self):
+    return len(self._get_rules())
+
   def __iter__(self):
     for rule in self._get_rules():
       yield rule
@@ -610,7 +652,7 @@ class ExitPolicyRule(object):
     # keyword or tor's default policy suffix.
 
     self._is_private = False
-    self._is_default_suffix = False  # TODO: implement
+    self._is_default_suffix = False
 
   def is_address_wildcard(self):
     """
@@ -754,6 +796,13 @@ class ExitPolicyRule(object):
 
     return self._is_private
 
+  def is_default(self):
+    """
+    True if this rule was part of the default end of a policy, False otherwise.
+    """
+
+    return self._is_default_suffix
+
   @lru_cache()
   def __str__(self):
     """
@@ -979,3 +1028,18 @@ class MicroExitPolicyRule(ExitPolicyRule):
       self._hash = my_hash
 
     return self._hash
+
+
+DEFAULT_POLICY_RULES = tuple([ExitPolicyRule(rule) for rule in (
+  '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 *:*',
+)])
diff --git a/test/unit/exit_policy/policy.py b/test/unit/exit_policy/policy.py
index b4a35e5..a1ee390 100644
--- a/test/unit/exit_policy/policy.py
+++ b/test/unit/exit_policy/policy.py
@@ -6,6 +6,7 @@ import pickle
 import unittest
 
 from stem.exit_policy import (
+  DEFAULT_POLICY_RULES,
   get_config_policy,
   ExitPolicy,
   MicroExitPolicy,
@@ -96,6 +97,18 @@ class TestExitPolicy(unittest.TestCase):
     policy = ExitPolicy('reject *:80-65535', 'accept *:1-65533', 'reject *:*')
     self.assertEquals('accept 1-79', policy.summary())
 
+  def test_non_private_non_default_policy(self):
+    policy = get_config_policy('reject *:80-65535, accept *:1-65533, reject *:*')
+
+    for rule in policy:
+      self.assertFalse(rule.is_private())
+      self.assertFalse(rule.is_default())
+
+    self.assertFalse(policy.is_default())
+
+    self.assertEqual(policy, policy.strip_private())
+    self.assertEqual(policy, policy.strip_default())
+
   def test_all_private_policy(self):
     for port in ('*', '80', '1-1024'):
       private_policy = get_config_policy('reject private:%s' % port)
@@ -110,13 +123,14 @@ class TestExitPolicy(unittest.TestCase):
     private_policy = get_config_policy('accept private:*')
     self.assertEqual(ExitPolicy(), private_policy.strip_private())
 
-  def test_all_non_private_policy(self):
-    nonprivate_policy = get_config_policy('reject *:80-65535, accept *:1-65533, reject *:*')
+  def test_all_default_policy(self):
+    policy = ExitPolicy(*DEFAULT_POLICY_RULES)
 
-    for rule in nonprivate_policy:
-      self.assertFalse(rule.is_private())
+    for rule in policy:
+      self.assertTrue(rule.is_default())
 
-    self.assertEqual(nonprivate_policy, nonprivate_policy.strip_private())
+    self.assertTrue(policy.is_default())
+    self.assertEqual(ExitPolicy(), policy.strip_default())
 
   def test_mixed_private_policy(self):
     policy = get_config_policy('accept *:80, reject private:1-65533, accept *:*')
@@ -126,6 +140,15 @@ class TestExitPolicy(unittest.TestCase):
 
     self.assertEqual(get_config_policy('accept *:80, accept *:*'), policy.strip_private())
 
+  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_str(self):
     # sanity test for our __str__ method
 





More information about the tor-commits mailing list