allow using of IPv6 address style mask (analog to the IPv4), for example: `2606:28ff::/ffff:ff80::` -> `2606:2880::/25`

fast calculating of maskplen using map table MAP_ADDR2MASKPLEN, with pre-calculated addr->maskplen values;
test cases extended;
pull/1415/head
sebres 2016-05-12 15:33:15 +02:00
parent 0c2eeee8c7
commit 4b5b16cd9f
2 changed files with 33 additions and 8 deletions

View File

@ -171,7 +171,7 @@ class IPAddr(object):
# IP address without CIDR mask # IP address without CIDR mask
if len(s) > 2: if len(s) > 2:
raise ValueError("invalid ipstr %r, too many plen representation" % (ipstr,)) raise ValueError("invalid ipstr %r, too many plen representation" % (ipstr,))
if "." in s[1]: # 255.255.255.0 style mask if "." in s[1] or ":" in s[1]: # 255.255.255.0 resp. ffff:: style mask
s[1] = IPAddr.masktoplen(s[1]) s[1] = IPAddr.masktoplen(s[1])
s[1] = long(s[1]) s[1] = long(s[1])
return s return s
@ -235,7 +235,7 @@ class IPAddr(object):
return self.ntoa return self.ntoa
def __reduce__(self): def __reduce__(self):
"""IPAddr pickle-handler, that simple wrap IPAddr to the str """IPAddr pickle-handler, that simply wraps IPAddr to the str
Returns a string as instance to be pickled, because fail2ban-client can't Returns a string as instance to be pickled, because fail2ban-client can't
unserialize IPAddr objects unserialize IPAddr objects
@ -392,17 +392,29 @@ class IPAddr(object):
return (self.addr & mask) == net.addr return (self.addr & mask) == net.addr
# Pre-calculated map: addr to maskplen
def __getMaskMap():
m6 = (1 << 128)-1
m4 = (1 << 32)-1
mmap = {m6: 128, m4: 32, 0: 0}
m = 0
for i in xrange(0, 128):
m |= 1 << i
if i < 32:
mmap[m ^ m4] = 32-1-i
mmap[m ^ m6] = 128-1-i
return mmap
MAP_ADDR2MASKPLEN = __getMaskMap()
@property @property
def maskplen(self): def maskplen(self):
mplen = 0 mplen = 0
if self._maskplen is not None: if self._maskplen is not None:
return self._maskplen return self._maskplen
maddr = self._addr mplen = IPAddr.MAP_ADDR2MASKPLEN.get(self._addr)
while maddr: if mplen is None:
if not (maddr & 0x80000000):
raise ValueError("invalid mask %r, no plen representation" % (str(self),)) raise ValueError("invalid mask %r, no plen representation" % (str(self),))
maddr = (maddr << 1) & 0xFFFFFFFFL
mplen += 1
self._maskplen = mplen self._maskplen = mplen
return mplen return mplen

View File

@ -1452,11 +1452,24 @@ class DNSUtilsNetworkTests(unittest.TestCase):
self.assertEqual(IPAddr('93.184.0.1', 24).ntoa, '93.184.0.0/24') self.assertEqual(IPAddr('93.184.0.1', 24).ntoa, '93.184.0.0/24')
self.assertEqual(IPAddr('192.168.1.0/255.255.255.128').ntoa, '192.168.1.0/25') self.assertEqual(IPAddr('192.168.1.0/255.255.255.128').ntoa, '192.168.1.0/25')
self.assertEqual(IPAddr('93.184.0.1/32').ntoa, '93.184.0.1')
self.assertEqual(IPAddr('93.184.0.1/255.255.255.255').ntoa, '93.184.0.1')
self.assertEqual(str(IPAddr('2606:2800:220:1:248:1893:25c8::', 120)), '2606:2800:220:1:248:1893:25c8:0/120') self.assertEqual(str(IPAddr('2606:2800:220:1:248:1893:25c8::', 120)), '2606:2800:220:1:248:1893:25c8:0/120')
self.assertEqual(IPAddr('2606:2800:220:1:248:1893:25c8::', 120).ntoa, '2606:2800:220:1:248:1893:25c8:0/120') self.assertEqual(IPAddr('2606:2800:220:1:248:1893:25c8::', 120).ntoa, '2606:2800:220:1:248:1893:25c8:0/120')
self.assertEqual(str(IPAddr('2606:2800:220:1:248:1893:25c8:0/120')), '2606:2800:220:1:248:1893:25c8:0/120') self.assertEqual(str(IPAddr('2606:2800:220:1:248:1893:25c8:0/120')), '2606:2800:220:1:248:1893:25c8:0/120')
self.assertEqual(IPAddr('2606:2800:220:1:248:1893:25c8:0/120').ntoa, '2606:2800:220:1:248:1893:25c8:0/120') self.assertEqual(IPAddr('2606:2800:220:1:248:1893:25c8:0/120').ntoa, '2606:2800:220:1:248:1893:25c8:0/120')
self.assertEqual(str(IPAddr('2606:28ff:220:1:248:1893:25c8::', 25)), '2606:2880::/25')
self.assertEqual(str(IPAddr('2606:28ff:220:1:248:1893:25c8::/ffff:ff80::')), '2606:2880::/25')
self.assertEqual(str(IPAddr('2606:28ff:220:1:248:1893:25c8::/ffff:ffff:ffff:ffff:ffff:ffff:ffff::')),
'2606:28ff:220:1:248:1893:25c8:0/112')
self.assertEqual(str(IPAddr('2606:28ff:220:1:248:1893:25c8::/128')),
'2606:28ff:220:1:248:1893:25c8:0')
self.assertEqual(str(IPAddr('2606:28ff:220:1:248:1893:25c8::/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')),
'2606:28ff:220:1:248:1893:25c8:0')
def testIPAddr_CIDR_Repr(self): def testIPAddr_CIDR_Repr(self):
self.assertEqual(["127.0.0.0/8", "::/32", "2001:db8::/32"], self.assertEqual(["127.0.0.0/8", "::/32", "2001:db8::/32"],
[IPAddr("127.0.0.0", 8), IPAddr("::1", 32), IPAddr("2001:db8::", 32)] [IPAddr("127.0.0.0", 8), IPAddr("::1", 32), IPAddr("2001:db8::", 32)]