自己动手编写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))

猜你喜欢

转载自www.cnblogs.com/guxh/p/10162951.html