Repository: qpid-dispatch Updated Branches: refs/heads/crolke-DISPATCH-188-1 3a766aebf -> 3e9a37ea5
Made HostStruct a class for external use. Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/3e9a37ea Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/3e9a37ea Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/3e9a37ea Branch: refs/heads/crolke-DISPATCH-188-1 Commit: 3e9a37ea5b838c2dca53611c70447aebc720552f Parents: 3a766ae Author: Chuck Rolke <[email protected]> Authored: Wed Dec 9 11:28:14 2015 -0500 Committer: Chuck Rolke <[email protected]> Committed: Wed Dec 9 11:28:14 2015 -0500 ---------------------------------------------------------------------- .../qpid_dispatch_internal/management/policy.py | 125 ++++++++++++------- tests/system_tests_policy.py | 53 ++++---- 2 files changed, 110 insertions(+), 68 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/3e9a37ea/python/qpid_dispatch_internal/management/policy.py ---------------------------------------------------------------------- diff --git a/python/qpid_dispatch_internal/management/policy.py b/python/qpid_dispatch_internal/management/policy.py index 2601ec5..8ba72dd 100644 --- a/python/qpid_dispatch_internal/management/policy.py +++ b/python/qpid_dispatch_internal/management/policy.py @@ -105,20 +105,13 @@ class PolicyError(Exception): # # -class HostAddr(): +class HostStruct(): """ - Provide HostIP address ranges and comparison functions. - A HostIP may be: - - single address: 10.10.1.1 - - a pair of addresses: 10.10.0.0,10.10.255.255 - Only IPv4 and IPv6 are supported. - - No unix sockets. - HostIP names must resolve to a single IP address. - Address pairs define a range. - - The second address must be numerically larger than the first address. - - The addresses must be of the same address 'family', IPv4 or IPv6. - IPv6 support is conditional based on underlying OS network options. - Raises a PolicyError on validation error in constructor. + HostStruct represents a single, binary socket address from getaddrinfo + - name : name given to constructor, numeric IP or host name + - saddr : net name resolved by getaddrinfo, numeric IP + - family : saddr.family, int + - binary : saddr packed binary address, binary string """ families = [socket.AF_INET] famnames = ["IPv4"] @@ -126,20 +119,15 @@ class HostAddr(): families.append(socket.AF_INET6) famnames.append("IPv6") - HostStruct = namedtuple("HostStruct", "text family binary") - - def has_ipv6(self): - return socket.has_ipv6 - - def parsehost(self, hostname): + def __init__(self, hostname): """ + Given a host name text string, return the socket info for it. @param[in] hostname host IP address to parse - @return HostStruct representing this host """ try: res = socket.getaddrinfo(hostname, 0) if len(res) == 0: - raise PolicyError("HostAddr.parsehost: '%s' did not resolve to an IP address" % hostname) + raise PolicyError("HostStruct: '%s' did not resolve to an IP address" % hostname) foundFirst = False saddr = "" sfamily = socket.AF_UNSPEC @@ -153,21 +141,55 @@ class HostAddr(): else: if family in self.families: if not saddr == sockaddr[0] or not sfamily == family: - raise PolicyError("HostAddr.parsehost: '%s' resolves to multiple IP addresses" % + raise PolicyError("HostStruct: '%s' resolves to multiple IP addresses" % hostname) if not foundFirst: - raise PolicyError("HostAddr.parsehost: '%s' did not resolve to one of the supported address family" % + raise PolicyError("HostStruct: '%s' did not resolve to one of the supported address family" % hostname) - packed = socket.inet_pton(family, saddr) - name = hostname - if not name == saddr: - name += "(" + saddr + ")" - return self.HostStruct(name, sfamily, packed) + self.name = hostname + self.saddr = saddr + self.family = sfamily + self.binary = socket.inet_pton(family, saddr) + return except Exception, e: - raise PolicyError("HostAddr.parsehost: '%s' failed to resolve: '%s'" % + raise PolicyError("HostStruct: '%s' failed to resolve: '%s'" % (hostname, e)) + def __str__(self): + return self.name + + def __repr__(self): + return self.__str__() + + def dump(self): + return ("(%s, %s, %s, %s)" % + (self.name, + self.saddr, + "AF_INET" if self.family == socket.AF_INET else "AF_INET6", + binascii.hexlify(self.binary))) + +# +# +class HostAddr(): + """ + Provide HostIP address ranges and comparison functions. + A HostIP may be: + - single address: 10.10.1.1 + - a pair of addresses: 10.10.0.0,10.10.255.255 + Only IPv4 and IPv6 are supported. + - No unix sockets. + HostIP names must resolve to a single IP address. + Address pairs define a range. + - The second address must be numerically larger than the first address. + - The addresses must be of the same address 'family', IPv4 or IPv6. + IPv6 support is conditional based on underlying OS network options. + Raises a PolicyError on validation error in constructor. + """ + + def has_ipv6(self): + return socket.has_ipv6 + def __init__(self, hostspec): """ Parse host spec into binary structures to use for comparisons. @@ -180,10 +202,9 @@ class HostAddr(): # hosts must contain one or two host specs if len(hosts) not in [1, 2]: raise PolicyError("hostspec must contain 1 or 2 host names") - - self.hoststructs.append(self.parsehost(hosts[0])) + self.hoststructs.append(HostStruct(hosts[0])) if len(hosts) > 1: - self.hoststructs.append(self.parsehost(hosts[1])) + self.hoststructs.append(HostStruct(hosts[1])) if not self.hoststructs[0].family == self.hoststructs[1].family: raise PolicyError("mixed IPv4 and IPv6 host specs in range not allowed") c0 = self.memcmp(self.hoststructs[0].binary, self.hoststructs[1].binary) @@ -199,16 +220,10 @@ class HostAddr(): def __repr__(self): return self.__str__() - def dumpstruct(self, hstruct): - return ("(%s, %s, %s)" % - (hstruct.text, - "AF_INET" if hstruct.family == socket.AF_INET else "AF_INET6", - binascii.hexlify(hstruct.binary))) - def dump(self): - res = "(" + self.dumpstruct(self.hoststructs[0]) + res = "(" + self.hoststructs[0].dump() if len(self.hoststructs) > 1: - res += "," + self.dumpstruct(self.hoststructs[1]) + res += "," + self.hoststructs[1].dump() res += ")" return res @@ -223,24 +238,40 @@ class HostAddr(): break return res - def match(self, candidate): + def match_bin(self, cstruct): """ - Does the candidate match the IP or range of IP addresses represented by this? - @param[in] candidate the IP address to be tested + Does the candidate hoststruct match the IP or range of IP addresses represented by this? + @param[in] cstruct the IP address to be tested @return candidate matches this or not """ try: - host = self.parsehost(candidate) - if not host.family == self.hoststructs[0].family: + if not cstruct.family == self.hoststructs[0].family: # sorry, wrong AF_INET family return False - c0 = self.memcmp(host.binary, self.hoststructs[0].binary) + c0 = self.memcmp(cstruct.binary, self.hoststructs[0].binary) if len(self.hoststructs) == 1: return c0 == 0 - c1 = self.memcmp(host.binary, self.hoststructs[1].binary) + c1 = self.memcmp(cstruct.binary, self.hoststructs[1].binary) return c0 >= 0 and c1 <= 0 except PolicyError: return False + except Exception, e: + assert isinstance(cstruct, HostStruct), \ + ("Wrong type. Expected HostStruct but received %s" % cstruct.__class__.__name__) + return False + + def match_str(self, candidate): + """ + Does the candidate string match the IP or range represented by this? + @param[in] candidate the IP address to be tested + @return candidate matches this or not + """ + try: + hoststruct = HostStruct(candidate) + except PolicyError: + return False + return self.match_bin(hoststruct) + # # class PolicyCompiler(): http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/3e9a37ea/tests/system_tests_policy.py ---------------------------------------------------------------------- diff --git a/tests/system_tests_policy.py b/tests/system_tests_policy.py index dece8c9..6e2878c 100644 --- a/tests/system_tests_policy.py +++ b/tests/system_tests_policy.py @@ -30,7 +30,7 @@ from proton.utils import BlockingConnection, LinkDetached from qpid_dispatch.management.client import Node from system_test import TIMEOUT -from qpid_dispatch_internal.management.policy import Policy, HostAddr, PolicyError +from qpid_dispatch_internal.management.policy import Policy, HostAddr, PolicyError, HostStruct class AbsoluteConnectionCountLimit(TestCase): """ @@ -82,23 +82,34 @@ class PolicyHostAddrTest(TestCase): def expect_deny(self, badhostname, msg): denied = False try: - xxx = HostAddr(badhostname) + xxx = HostStruct(badhostname) except PolicyError: denied = True - self.assertTrue(denied) # msg + self.assertTrue(denied, ("%s" % msg)) + + def check_hostaddr_match(self, tHostAddr, tString, expectOk=True): + # check that the string is a match for the addr + # check that the internal struct version matches, too + ha = HostStruct(tString) + if expectOk: + self.assertTrue( tHostAddr.match_str(tString) ) + self.assertTrue( tHostAddr.match_bin(ha) ) + else: + self.assertFalse( tHostAddr.match_str(tString) ) + self.assertFalse( tHostAddr.match_bin(ha) ) def test_policy_hostaddr_ipv4(self): # Create simple host and range aaa = HostAddr("192.168.1.1") bbb = HostAddr("1.1.1.1,1.1.1.255") # Verify host and range - self.assertTrue ( aaa.match("192.168.1.1") ) - self.assertFalse( aaa.match("1.1.1.1") ) - self.assertFalse( aaa.match("192.168.1.2") ) - self.assertTrue ( bbb.match("1.1.1.1") ) - self.assertTrue ( bbb.match("1.1.1.254") ) - self.assertFalse( bbb.match("1.1.1.0") ) - self.assertFalse( bbb.match("1.1.2.0") ) + self.check_hostaddr_match(aaa, "192.168.1.1") + self.check_hostaddr_match(aaa, "1.1.1.1", False) + self.check_hostaddr_match(aaa, "192.168.1.2", False) + self.check_hostaddr_match(bbb, "1.1.1.1") + self.check_hostaddr_match(bbb, "1.1.1.254") + self.check_hostaddr_match(bbb, "1.1.1.0", False) + self.check_hostaddr_match(bbb, "1.1.2.0", False) def test_policy_hostaddr_ipv6(self): if not HostAddr.has_ipv6: @@ -108,17 +119,17 @@ class PolicyHostAddrTest(TestCase): bbb = HostAddr("::1,::ffff") ccc = HostAddr("ffff::0,ffff:ffff::0") # Verify host and range - self.assertTrue ( aaa.match("::1") ) - self.assertFalse( aaa.match("::2") ) - self.assertFalse( aaa.match("ffff:ffff::0") ) - self.assertTrue ( bbb.match("::1") ) - self.assertTrue ( bbb.match("::fffe") ) - self.assertFalse( bbb.match("::1:0") ) - self.assertFalse( bbb.match("ffff::0") ) - self.assertTrue ( ccc.match("ffff::1") ) - self.assertTrue ( ccc.match("ffff:fffe:ffff:ffff::ffff") ) - self.assertFalse( ccc.match("ffff:ffff:1") ) - self.assertFalse( ccc.match("ffff:ffff:ffff:ffff::ffff") ) + self.check_hostaddr_match(aaa, "::1") + self.check_hostaddr_match(aaa, "::2", False) + self.check_hostaddr_match(aaa, "ffff:ffff::0", False) + self.check_hostaddr_match(bbb, "::1") + self.check_hostaddr_match(bbb, "::fffe") + self.check_hostaddr_match(bbb, "::1:0", False) + self.check_hostaddr_match(bbb, "ffff::0", False) + self.check_hostaddr_match(ccc, "ffff::1") + self.check_hostaddr_match(ccc, "ffff:fffe:ffff:ffff::ffff") + self.check_hostaddr_match(ccc, "ffff:ffff::1", False) + self.check_hostaddr_match(ccc, "ffff:ffff:ffff:ffff::ffff", False) def test_policy_malformed_hostaddr_ipv4(self): self.expect_deny( "0.0.0.0.0", "Name or service not known") --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
