[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