commit 54d2c103940b31195b3c91ac440d7f07cb6b9489 Author: Damian Johnson atagar@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)
tor-commits@lists.torproject.org