[tor-commits] [stem/master] Function to parse configuration exit policies

atagar at torproject.org atagar at torproject.org
Mon Jan 14 01:39:16 UTC 2013


commit 54d2c103940b31195b3c91ac440d7f07cb6b9489
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Jan 13 12:57:02 2013 -0800

    Function to parse configuration exit policies
    
    Tor exit policies found in the torrc (and 'GETCONF ExitPolicy') differ slightly
    from the exitpattern definition found in the spec. Adding a get_config_policy()
    function that converts these into proper exit policies.
---
 stem/exit_policy.py             |   58 +++++++++++++++++++++++++++++++++++++--
 test/unit/exit_policy/policy.py |   44 +++++++++++++++++++++++++++++-
 2 files changed, 98 insertions(+), 4 deletions(-)

diff --git a/stem/exit_policy.py b/stem/exit_policy.py
index 923b700..45e0a98 100644
--- a/stem/exit_policy.py
+++ b/stem/exit_policy.py
@@ -56,9 +56,21 @@ import stem.util.enum
 
 AddressType = stem.util.enum.Enum(("WILDCARD", "Wildcard"), ("IPv4", "IPv4"), ("IPv6", "IPv6"))
 
-# TODO: The ExitPolicyRule's exitpatterns are used everywhere except the torrc.
-# This is fine for now, but we should add a subclass to handle those slight
-# differences later if we want to provide the ability to parse torrcs.
+# Addresses aliased by the 'private' policy. From the tor man page...
+#
+# To specify all internal and link-local networks (including 0.0.0.0/8,
+# 169.254.0.0/16, 127.0.0.0/8, 192.168.0.0/16, 10.0.0.0/8, and 172.16.0.0/12),
+# you can use the "private" alias instead of an address.
+
+PRIVATE_ADDRESSES = (
+  "0.0.0.0/8",
+  "169.254.0.0/16",
+  "127.0.0.0/8",
+  "192.168.0.0/16",
+  "10.0.0.0/8",
+  "172.16.0.0/12",
+)
+
 
 # TODO: The ExitPolicyRule could easily be a mutable class if we did the
 # following...
@@ -75,6 +87,46 @@ AddressType = stem.util.enum.Enum(("WILDCARD", "Wildcard"), ("IPv4", "IPv4"), ("
 # some use cases where we might want to construct custom policies. Maybe make
 # it a CustomExitPolicyRule subclass?
 
+def get_config_policy(rules):
+  """
+  Converts an ExitPolicy found in a torrc to a proper exit pattern. This
+  accounts for...
+
+  * ports being optional
+  * the 'private' keyword
+
+  :param str,list rules: comma separated rules or list to be converted
+
+  :returns: **list** of :class:`~stem.exit_policy.ExitPolicyRule`
+
+  :raises: **ValueError** if input isn't a valid tor exit policy
+  """
+
+  if isinstance(rules, str):
+    rules = rules.split(',')
+
+  result = []
+
+  for rule in rules:
+    rule = rule.strip()
+
+    if not rule:
+      continue
+
+    if not ':' in rule:
+      rule = "%s:*" % rule
+
+    if 'private' in rule:
+      acceptance = rule.split(' ', 1)[0]
+      port = rule.split(':', 1)[1]
+
+      for private_addr in PRIVATE_ADDRESSES:
+        result.append(ExitPolicyRule("%s %s:%s" % (acceptance, private_addr, port)))
+    else:
+      result.append(ExitPolicyRule(rule))
+
+  return result
+
 
 class ExitPolicy(object):
   """
diff --git a/test/unit/exit_policy/policy.py b/test/unit/exit_policy/policy.py
index c22eab0..4da21b0 100644
--- a/test/unit/exit_policy/policy.py
+++ b/test/unit/exit_policy/policy.py
@@ -4,7 +4,8 @@ Unit tests for the stem.exit_policy.ExitPolicy class.
 
 import unittest
 
-from stem.exit_policy import ExitPolicy, \
+from stem.exit_policy import get_config_policy, \
+                             ExitPolicy, \
                              MicroExitPolicy, \
                              ExitPolicyRule
 
@@ -190,3 +191,44 @@ class TestExitPolicy(unittest.TestCase):
 
     self.assertFalse(policy.can_exit_to('127.0.0.1', 79))
     self.assertTrue(policy.can_exit_to('127.0.0.1', 80))
+
+  def test_get_config_policy(self):
+    test_inputs = {
+      "": [],
+      "reject *": [
+        ExitPolicyRule('reject *:*'),
+      ],
+      "reject *:*": [
+        ExitPolicyRule('reject *:*'),
+      ],
+      "reject private": [
+        ExitPolicyRule('reject 0.0.0.0/8:*'),
+        ExitPolicyRule('reject 169.254.0.0/16:*'),
+        ExitPolicyRule('reject 127.0.0.0/8:*'),
+        ExitPolicyRule('reject 192.168.0.0/16:*'),
+        ExitPolicyRule('reject 10.0.0.0/8:*'),
+        ExitPolicyRule('reject 172.16.0.0/12:*'),
+      ],
+      "accept *:80, reject *": [
+        ExitPolicyRule('accept *:80'),
+        ExitPolicyRule('reject *:*'),
+      ],
+      "  accept *:80,     reject *   ": [
+        ExitPolicyRule('accept *:80'),
+        ExitPolicyRule('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)





More information about the tor-commits mailing list