2

I want to convert a list of IPs to a list of corresponding IP ranges. For example:

iplist = ['137.226.161.121', '134.130.4.1', '137.226.161.149', '137.226.161.221', '137.226.161.240', '137.226.161.237', '8.8.8.8', '8.8.4.4', '137.226.161.189', '137.226.161.245', '137.226.161.172', '137.226.161.241', '137.226.161.234', '137.226.161.236', '134.130.5.1']

to

ipranges = ['137.226.161.0/24', '134.130.4.0/24', '8.8.8.0/24', '8.8.4.0/24', '134.130.5.0/24']

What is the most efficient way of doing this? I haven't found a module that offers a function like that. The reason for this function is that a long list of IPs (over 1000 ips) should be converted into a list of subnets to improve readability.

Thank you

freak14
  • 33
  • 5

2 Answers2

4

If I understand you correctly, you only want to match based on the first 24 bits (/24) being identical. For these tasks I recommend a set:

iplist = ['137.226.161.121', '134.130.4.1', '137.226.161.149', '137.226.161.221', '137.226.161.240', '137.226.161.237', '8.8.8.8', '8.8.4.4', '137.226.161.189', '137.226.161.245', '137.226.161.172', '137.226.161.241', '137.226.161.234', '137.226.161.236', '134.130.5.1']

ipset = set()
for i in iplist:
    ipset.add(".".join(i.split(".")[:-1]))

ipranges = [p + ".0/24" for p in ipset]
print(ipranges)

This prints: ['134.130.5.0/24', '8.8.4.0/24', '8.8.8.0/24', '134.130.4.0/24', '137.226.161.0/24']

So what does this code do?

First, we iterate through the list and cut off the last segment of each IP:

segments = "8.8.8.8".split(".")  # segments == ["8", "8", "8", "8"]
segments_cut = segments[:-1]     # segments_cut == ["8", "8", "8"]
prefix = ".".join(segments_cut)  # prefix == "8.8.8"

Now we add these prefixes to the set. A Python set only allows unique elements. This results in: ìpset == {'134.130.5', '8.8.4', '8.8.8', '134.130.4', '137.226.161'}

Finally we iterate through the set and append the suffix ".0/24" to denote a subnet.

Edit: About "efficiency"

I like the answer by darkless, but just know that my solution is significantly faster (1.2 s vs 0.09 s):

>>> import timeit
>>> # darkless' ipaddress solution
>>> timeit.timeit("[str(ipaddress.ip_network('{}/24'.format(ip), strict=False)) for ip in iplist]", setup="import ipaddress;iplist = ['137.226.161.121', '134.130.4.1', '137.226.161.149', '137.226.161.221', '137.226.161.240', '137.226.161.237', '8.8.8.8', '8.8.4.4', '137.226.161.189', '137.226.161.245', '137.226.161.172', '137.226.161.241', '137.226.161.234', '137.226.161.236', '134.130.5.1']", number=10000)
1.186...
>>> # My solution
>>> timeit.timeit("[p + '.0/24' for p in {'.'.join(i.split('.')[:-1]) for i in iplist}]", setup="import ipaddress;iplist = ['137.226.161.121', '134.130.4.1', '137.226.161.149', '137.226.161.221', '137.226.161.240', '137.226.161.237', '8.8.8.8', '8.8.4.4', '137.226.161.189', '137.226.161.245', '137.226.161.172', '137.226.161.241', '137.226.161.234', '137.226.161.236', '134.130.5.1']", number=10000)
0.096...
vauhochzett
  • 2,732
  • 2
  • 17
  • 40
1

As Hampus Larsson mentioned, you can use python ipaddress module:

import ipaddress

iplist = ['137.226.161.121', '134.130.4.1', '137.226.161.149', '137.226.161.221', '137.226.161.240', '137.226.161.237', '8.8.8.8', '8.8.4.4', '137.226.161.189', '137.226.161.245', '137.226.161.172', '137.226.161.241', '137.226.161.234', '137.226.161.236', '134.130.5.1']

ipranges = [str(ipaddress.ip_network('{}/24'.format(ip), strict=False)) for ip in iplist]

>>> ipranges
['137.226.161.0/24', '134.130.4.0/24', '137.226.161.0/24', '137.226.161.0/24', '137.226.161.0/24', '137.226.161.0/24', '8.8.8.0/24', '8.8.4.0/24', '137.226.161.0/24', '137.226.161.0/24', '137.226.161.0/24', '137.226.161.0/24', '137.226.161.0/24', '137.226.161.0/24', '134.130.5.0/24']

darkless
  • 1,304
  • 11
  • 19