netaddr / netaddr

A network address manipulation library for Python

Home Page:https://netaddr.readthedocs.io/en/latest/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The 'IPNetwork.subnet' function can loop through 2 ^ 128 elements

sebastien-rosset opened this issue · comments

The subnet() function may loop through 2 ^ N elements, where N <= 128.
The subnet function may be invoked for a IPv6 network such as 2600:1f1c:1b3:8f00::/56, count = None and prefix length /120. It calculates the max number of subnets:

width = self._module.width
max_subnets = 2 ** (width - self.prefixlen) // 2 ** (width - prefixlen)

If the network address is /0 and the prefix length is 128, then max_subnets = 2 ^ 128 // 2 ^ 0, which is 2 ^ 128. If the count argument is set to 0, this will cause unbounded CPU usage and memory allocation, netaddr.subnet never returns.

Hey @sebastien-rosset, thank you for the report. It seems to be me that this is behaving as expected – the generator yields the subnets that are actually requested.

If the count argument is set to 0, this will cause unbounded CPU usage and memory allocation, netaddr.subnet never returns

I failed to reproduce this. subnet() returns immediately, it returns a generator. The generator then can be iterated (the memory use will remain constant unless the client code stores the results somewhere) or discarded after however many iterations the client code desires. See below:

>>> from netaddr import IPNetwork
>>> net = IPNetwork('2600:1f1c:1b3:8f00::/56')
>>> subnets = net.subnet(128)
>>> 
>>> subnets
<generator object IPNetwork.subnet at 0x101488970>
>>> next(subnets)
IPNetwork('2600:1f1c:1b3:8f00::/128')
>>> next(subnets)
IPNetwork('2600:1f1c:1b3:8f00::1/128')
>>> next(subnets)
IPNetwork('2600:1f1c:1b3:8f00::2/128')
>>> next(subnets)
IPNetwork('2600:1f1c:1b3:8f00::3/128')
>>> next(subnets)