1. 程式人生 > >自己動手編寫IPv4地址包含關係測試的小指令碼

自己動手編寫IPv4地址包含關係測試的小指令碼

工作中需要對地址包含關係進行測試,現有ipaddress標準庫和IPy無法滿足,於是自己動手編寫小指令碼,主要實現== , in, <等專用功能,其他功能可以後續用到再補充,例如迭代列印網段內所有地址,輸出字首長度等等。

一,含有的類:
Host類:主機地址,eg, Host('192.168.1.1')
Network類:網路地址,eg,Network('192.168.1.0 255.255.255.0')
AddressGroup類:主機地址和網路地址組成的列表,eg,AddressGroup(['192.168.1.0 255.255.255.0', '10.1.1.1'])

二,可以實現的in測試功能:
1)地址與網段的測試,地址與字首+萬用字元的測試:
Host('192.168.1.1') in Network('192.168.1.0 255.255.255.0') # True
Host('192.12.1.5') in Network('192.0.1.0 255.0.255.0') # True

2)網段與網段的測試,網段與地址+萬用字元的測試:
Network(192.168.1.0 255.255.255.0) in Network('192.168.0.0 255.255.0.0') # True
Network(192.0.1.0 255.0.255.0) in Network('192.168.0.0 255.255.0.0') # False

3)地址/網段組,與地址/網段組的測試:
AddressGroup(['192.168.1.0 255.255.255.0', '10.1.1.1']) < AddressGroup(['192.168.0.0 255.255.255.0', '10.1.1.1']) # True

4)字首修正
n1 = Network('192.168.1.0 255.0.255.0')
n1.network # 192.0.1.0

三,由於資料來源都是標準的地址格式,因此很多細節和出錯控制未考慮:
Address('300.1000.2.1') # 未做地址或者網段的出錯控制,僅控制了split('.')是否等於4以及元素是否是整數

class AddressValueError(ValueError):
    """A Value Error related to the netmask."""


def ip_address(address):
    try:
        return
Host(address) except AddressValueError: pass try: return Network(address) except AddressValueError: pass raise AddressValueError('Not a valid host or network address: {!r}'.format(address)) def _host_int_from_string(address): octets = address.split('.') if len(octets) != 4: raise AddressValueError("Expected 4 octets in {!r}".format(address)) try: return [int(i) for i in octets] except ValueError as exc: raise AddressValueError("%s in %r" % (exc, address)) from None def _network_int_from_string(address): parts = address.split() if len(parts) != 2: raise AddressValueError("Expected network plus netmask in {!r}".format(address)) return _host_int_from_string(parts[0]), _host_int_from_string(parts[1]) class Host(object): """eg, address: 192.168.1.1""" __slots__ = ('_address', '_host') def __init__(self, address): self._address= address self._host = _host_int_from_string(address) def __repr__(self): return '<Host:{!r}>'.format(self._address) def __eq__(self, other): try: return self._address == other._address except AttributeError: return NotImplemented class Network(object): """eg, address: 192.168.1.0 255.255.255.0""" __slots__ = ('_address', '_network', '_netmask') def __init__(self, address): self._address = address self._network, self._netmask = _network_int_from_string(address) self._network = [i[0] & i[1] for i in zip(self._network, self._netmask)] def __repr__(self): return '<Network:{!r}>'.format(self._address) def __eq__(self, other): try: return self._network == other._network and self._netmask == other._netmask except AttributeError: return NotImplemented def __contains__(self, other): if isinstance(other, Host): network_other = [i[0] & i[1] for i in zip(other._host, self._netmask)] if self._network == network_other: return True elif isinstance(other, Network): parts = [i[0] & i[1] for i in zip(other._network, self._netmask)] if parts == self._network and all([i[1] >= i[0] for i in zip(self._netmask, other._netmask)]): return True return False @property def network(self): return '.'.join([str(i) for i in self._network]) class AddressGroup(object): """ eg,address_group: ['192.168.1.1', '192.168.1.2', '10.1.1.0 255.255.255.0'] 無法繼承abc.Set自動獲取lt方法(只要實現len/iter/contains),因為abc.Set中兩個Set長度相等直接返回Fasle,本類不一定,因此需要自己編寫__lt__特殊方法 """ def __init__(self, components): self._components = components self._compObjs = [ip_address(i) for i in components] def __len__(self): return len(self._components) def __iter__(self): for c in self._compObjs: yield c def __contains__(self, other): if isinstance(other, Host): for obj in self: cond1 = isinstance(obj, Host) and other == obj cond2 = isinstance(obj, Network) and other in obj if cond1 or cond2: return True if isinstance(other, Network): for obj in self: if isinstance(obj, Network) and other in obj: return True return False def __eq__(self, other): try: return sorted(self._components) == sorted(other._components) except AttributeError: return NotImplemented def __lt__(self, other): return all([i in other for i in self._compObjs]) def __repr__(self): return '<AddressGroup:{!r}>'.format(' | '.join(self._components))