"""Collections of distinct ip-addresses.
"""
import struct
import base64
import ipaddr
[docs]class IPList(object):
"""List (well, actually more of a set) of ip-addresses (well, actually
using subnets...).
"""
def __init__(self, iterable=()):
self._addys = set()
for ipaddy in iterable:
self.add(ipaddy)
[docs] def add(self, ipaddy):
"Add ipaddy to self."
if isinstance(ipaddy, str):
ipaddy = ipaddr.IPv4Address(ipaddy)
self._addys.add(ipaddy)
[docs] def network(self):
"Return the list of networks that cover our list of ip-addys."
return ipaddr.collapse_address_list(self._addys)
def __iter__(self):
"Iterate over all network addresses in self."
for ipaddy in sorted(self._addys):
yield ipaddy
def __eq__(self, other):
# pylint:disable=W0212
return len(self._addys ^ other._addys) == 0
[docs] def pack(self):
"""Convert to compressed, but db friendly, notation.
This fits ~124 ip addys into 250 bytes, if they are sufficiently
contigous.
"""
pstr = ''.join([a.packed for a in self])
pzip = pstr.encode('zip')
b64val = base64.urlsafe_b64encode(pzip)
return b64val
[docs] def unpack(self, b64val):
"Reverse steps in pack()."
pzip = base64.urlsafe_b64decode(b64val)
pstr = pzip.decode('zip')
while pstr:
val, pstr = pstr[:4], pstr[4:]
self.add(ipaddr.IPv4Address(struct.unpack("!I", val)[0]))
__getstate__ = pack
__setstate__ = unpack
def __json__(self):
return [a.compressed for a in self]
def __repr__(self):
return 'IPList(%r)' % list(self)
def __str__(self):
return ', '.join([a.compressed for a in self])