Search code examples
pythonip-addressipv4

may ipaddress.collapse_addresses() collapse for more than 1 bit of the mask?


Why does:

>>> import ipaddress
>>> print [ip for ip in ipaddress.collapse_addresses([ipaddress.IPv4Network(u'192.0.128.0/24'), ipaddress.IPv4Network(u'192.0.129.0/24')])]
[IPv4Network(u'192.0.128.0/23')]

but:

>>> print [ip for ip in ipaddress.collapse_addresses([ipaddress.IPv4Network(u'192.0.129.0/24'), ipaddress.IPv4Network(u'192.0.130.0/24')])]
[IPv4Network(u'192.0.129.0/24'), IPv4Network(u'192.0.130.0/24')]

What I am trying to achieve:

>>> print [ip for ip in ipaddress.collapse_addresses([ipaddress.IPv4Network(u'192.0.129.0/24'), ipaddress.IPv4Network(u'192.0.130.0/24')])]
[IPv4Network(u'192.0.128.0/22')]

It seems like collapse_addresses cannot collapse for more than 1 bit of the mask.


Solution

  • This function returns the smallest network that contain the ipv4 networks of a list:

    ADDRESS_ANY = ip_address(u'0.0.0.0')
    def one_net(subnets):
        """
        Get the one IP network that covers all subnets in input,
        or None is subnets are disjoint.
        """
        if len(subnets) == 0:
            return None
    
        minlen = min([net.prefixlen for net in subnets])
        while subnets.count(subnets[0]) < len(subnets) and minlen > 0:
            # all subnets are not (yet) equal
            subnets = [net.supernet(new_prefix=minlen) for net in subnets]
            minlen -= 1
    
        # 0.0.0.0/? -> no common subnet
        if subnets[0].network_address == ADDRESS_ANY:
            return None
        return subnets[0]