I am trying to create a script that generates a list of IP addresses based on a users input for a start and end IP range. For example, they could enter 192.168.1.25 & 1
It'd be easier to use a format like nmap
's:
192.168.1.1-255
As now, you can do:
octets = '192.168.1.1-255'.split('.')
parsed_ranges = [map(int, octet.split('-')) for octet in octets]
parsed_ranges
will look like [[192], [168], [1], [1, 255]]
. From there, generating the addresses is simple with itertools
:
import itertools
ranges = [range(r[0], r[1] + 1) if len(r) == 2 else r for r in parsed_ranges]
addresses = itertools.product(*ranges)
Here's a simple implementation:
import itertools
def ip_range(input_string):
octets = input_string.split('.')
chunks = [map(int, octet.split('-')) for octet in octets]
ranges = [range(c[0], c[1] + 1) if len(c) == 2 else c for c in chunks]
for address in itertools.product(*ranges):
yield '.'.join(map(str, address))
And the result:
>>> for address in ip_range('192.168.1-2.1-12'): print(address)
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
192.168.1.5
192.168.1.6
192.168.1.7
192.168.1.8
192.168.1.9
192.168.1.10
192.168.1.11
192.168.1.12
192.168.2.1
192.168.2.2
192.168.2.3
192.168.2.4
192.168.2.5
192.168.2.6
192.168.2.7
192.168.2.8
192.168.2.9
192.168.2.10
192.168.2.11
192.168.2.12
Remember that a dotted IPv4-address "x.x.x.x" is nothing more than a human-readable representation of a 32-bit integer. Using this, you can generate the ranges like this:
def undotIPv4 (dotted):
return sum (int (octet) << ( (3 - i) << 3) for i, octet in enumerate (dotted.split ('.') ) )
def dotIPv4 (addr):
return '.'.join (str (addr >> off & 0xff) for off in (24, 16, 8, 0) )
def rangeIPv4 (start, stop):
for addr in range (undotIPv4 (start), undotIPv4 (stop) ):
yield dotIPv4 (addr)
for x in rangeIPv4 ('1.2.3.4', '1.2.4.22'):
print (x)