0

I have a dataframe with IPv4 and IPv6 CIDR IP address ranges (these can be split up if necessary) in a data frame. I am hoping to take those ranges and create a data frame with each address in the range, so I can join that with another data frame to do some filtering.

Using the ipaddress package, the function to expand a list is:

a = ip.ip_network('103.21.244.0/22')
    for x in a.hosts():
    print(x)

This yields a list for just this IP range. Does anyone know how to put in a series of CIDR ranges so I don't have to perform the above n times? If I put a reference to the data frame in place of the IP address above, I get a ValueError stating that it doesn't appear to be an IPv4 or IPv6 network.

The secondary question, as a Python newbie, what do I need to do to get these expanded ranges into a list or data frame? I tried this:

a = ip.ip_network('103.21.244.0/22')
ip_list = [] #x for x in a.hosts()
for x in a.hosts():
    ip_list.append(x)
ip_list

And ended up with:

[IPv4Address('103.21.244.1'),
 IPv4Address('103.21.244.2'),
 IPv4Address('103.21.244.3'),
 IPv4Address('103.21.244.4'),
 IPv4Address('103.21.244.5'),
 ...]

I'm sure there is a better way than taking that output and regexing the IP addresses.

Ken Wallace
  • 2,261
  • 2
  • 13
  • 13

2 Answers2

0
a = ip.ip_network('103.21.244.0/22')
ip_list = [] #x for x in a.hosts()
for x in a.hosts():
    ip_list.append(x.compressed) # 
ip_list
0

About the first question, I'm afraid you can't do it if the module doesn't support it, and I don't think it does given the docs. Python offers two ways to apply a method to a list besides the traditional for loop:

The map() way, applies an operation to all the items of a list and returns a generator of the results:

def get_single_ip_from_cidr(cidr):
    # ...
cidr_list = ["10.0.0.0/8","192.168.0.0/16"]
results_generator = map(get_single_ip_from_cidr, cidr_list)
print(list(results_generator)) # Casting results_generator to list as you cant print generators directly

The pythonic way with List comprehensions:

def get_single_ip_from_cidr(cidr):
    # ...
results = [get_single_ip_from_cidr(cidr_addr) for cidr_addr in cidr_list] 

About the second question, the list you get is a list of IPv4Address objects, you are just seeing a stringified representation of it. By using help(ipaddress.IPv4Address), you can see that is has two attributes named compressed and exploded that both yield what you want (I'm assuming the difference between the two is only relevant in IPv6 where you can use :: as a shorthand for a group of zeroes):

a = ip.ip_network('103.21.244.0/22')
ip_list = [addr.compressed for addr in a.hosts()]

Jeff's answer is doing exactly the same thing but is more verbose.

So, you can refactor your entire code to get all hosts from a list of networks like so:

import ipaddress as ip

def get_ip_from_cidr(cidr):
    return [addr.compressed for addr in ip.ip_network(cidr)]

cidr_list = ["192.168.0.0/30","10.0.0.0/26"] 
print([get_ip_from_cidr(cidr) for cidr in cidr_list])
anto418
  • 176
  • 1
  • 13