5

The brute force approach:

from ipaddr import IPv4Network
n = IPv4Network('10.10.128.0/17')
all = list(n.iterhosts()) # will give me all hosts in network
first,last = all[0],all[-1] # first and last IP

I was wondering how I would get the first and last IP address from a CIDR without having to iterate over a potentially very large list to get the first and last element?

I want this so I can then generate a random ip address in this range using something like this:

socket.inet_ntoa(struct.pack('>I', random.randint(int(first),int(last))))
aaa90210
  • 11,295
  • 13
  • 51
  • 88

3 Answers3

8

From Python 3.3, you can use the ipaddress module

You could use it like this:

import ipaddress

n = ipaddress.IPv4Network('10.10.128.0/17')
first, last = n[0], n[-1]

__getitem__ is implemented, so it won't generate any large lists.

https://github.com/python/cpython/blob/3.6/Lib/ipaddress.py#L634

bsa
  • 2,671
  • 21
  • 31
  • I like this solution because it uses standard libraries, and is Pythonic precisely because of ```__getitem__``` and the efficiency of getting first and last (thanks to @bsa for pointing this out). The OP @aaa90210 isn't precise about exactly what the application is so OP may have wanted the network and broadcast which this will return. For my application I wanted first and last IP in the range and ```first, last = n[1], n[-2]``` worked well for me. – Justin Haynes Jan 20 '22 at 15:45
4

Maybe try netaddr instead, in particular the indexing section.

https://pythonhosted.org/netaddr/tutorial_01.html#indexing

from netaddr import *
import pprint

ip = IPNetwork('10.10.128.0/17')

print "ip.cidr = %s" % ip.cidr
print "ip.first.ip = %s" % ip[0]
print "ip.last.ip = %s" % ip[-1]
kiwi_gem81
  • 106
  • 4
  • Oops...looks like ipaddr module supports this method as well! I should have tried that. I used ipaddr over netaddr as I found the former had more reliable operations for checking overlapping CIDRs. – aaa90210 Nov 01 '16 at 21:51
3

The python 3 ipaddress module is the more elegant solution, imho. And, by the way, it works fine, but the ipaddress module doesn't return exactly the first and last free ip addresses at indexes [0,-1], but respectively the network address and the broadcast address.

The first and last free and assignable addresses are rather

import ipaddress

n = ipaddress.IPv4Network('10.10.128.0/17')
first, last = n[1], n[-2]

which will return 10.10.128.1 as first and 10.10.255.254 instead of 10.10.128.0 and 10.10.255.255

Sebisme
  • 31
  • 1