# Je t’embrasseSalutations from Silicon Valley, California

25Nov/090

I have frequently run up against the problem of generating network addresses (strictly speaking IPv4) but I am positive that the principles demonstrated below can carry over into IPv6.

The biggest issue is that in calculating addresses, the best way to find the "Nth address from here" is to convert to decimal and add. Well it's not so difficult to convert 4 octets into a 32-bit binary number, and crunch that into a single decimal number, add "N", convert back to binary, divide into octets, and convert back to decimal... but it takes forever. So why take forever when you don't need to. The trick? Divide & Conquer.

After walking through the theory, masks, addresses, ranges, compliments... I finally put together the following as a helper. Feel free to comment.

```#!/usr/bin/env python

import re
import sys
from optparse import OptionParser

# ============================================================================
# Global Variables
# ============================================================================
use_string = "usage: %prog"
ver_string = "v.0.1.0"

# ============================================================================
# Global Functions
# ============================================================================
def is_ipv4(string):
regex = r'^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)\$'
i = re.finditer(regex,string)
match = [m.groups() for m in i]
if len(match) != 1: return False
octets = match[0]
for octet in octets:
try: number = int(octet)
except: return False
if number < 0 or number > 255: return False
return True

def dec2octets(number):
original = number
octets = 4
remainder = 1
while (remainder != 0):
if octets == 0:
raise Exception("'%s' is too large to be an IP."%original)
octets = octets - 1
value = number / (256**octets)
remainder = number % (256**octets)
number = remainder

def ip2list(ip):
assert is_ipv4(ip)
return [int(x) for x in ip.split('.')]

def ip2bin(ip):
assert is_ipv4(ip)
tmp = [[('0','1')[x>>j&1] for j in xrange(7,-1,-1)] \
for x in [int(x) for x in ip.split('.')]]
return ''.join([''.join(x) for x in tmp])

def bin2dec(x):
assert type(x) == type("")
assert x.strip('01') == ''
return int(x,2)

def numify(n):
assert type(n) == type(1)
if str(n)[-1] == "1": return "%sst"%(n)
elif str(n)[-1] == "2": return "%snd"%(n)
elif str(n)[-1] == "3": return "%srd"%(n)
else: return "%sth"%(n)

# ============================================================================
# Main Method
# ============================================================================
if __name__ == '__main__':
parser = OptionParser(version=ver_string, usage=use_string)
action="store",
default=None,
help=("Use this to specify the IP address to use in "
"calculations. Alternatively, specify the IP address"
"in the 'x.x.x.x/N' form to specify both IP and "
)
action="store",
default=None,
help=("Use this to specify the subnet mask to use in "
"calculations."),
)
action="store",
default=0,
dest="lookFor",
help=("Use this to specify the IP address to "
"us in calculations"),
metavar="VALUE",
)

(options, args) = parser.parse_args()

# ========================================================================
# Massage input...
# ========================================================================
comp = [255-x for x in mask]
cast = [comp[x] | netw[x] for x in range(len(comp))]
assert is_ipv4(temp)
assert int(bits) < 32
assert int(bits) > 0
bits = int(bits)
temp = "".join(["1"]*bits)+"".join(["0"]*(32-bits))
bin2dec(temp[16:24]), bin2dec(temp[24:32])]
comp = [255-x for x in mask]
cast = [comp[x] | netw[x] for x in range(len(comp))]
comp = [255-x for x in mask]
cast = [comp[x] | netw[x] for x in range(len(comp))]
else: raise Exception("An IP or Subnet mask must be specified!")
diff = dec2octets(int(options.lookFor))
size = bin2dec("".join(["1"]*(32-bits)))-1

# Is it valid? (aka. Is it in our specified range?)
test =  & mask[x] for x in range(len(diff))]

# ========================================================================
# Massage output...
# ========================================================================
network = ".".join([str(x) for x in netw])
brdcast = ".".join([str(x) for x in cast])
print ("There are %s addresses available in the %s/%s network "
"range."%(size, network, bits))

print ("Network: %s  Netmask: %s  "

if (int(options.lookFor) <= 0): sys.exit()
if (test == [0,0,0,0]):
plus = ".".join([str(netw[x] + diff[x]) for x in range(len(netw))])
print ("The %s address in the %s/%s network "
"is %s"%(numify(int(options.lookFor)), network, bits, plus))
else:
print ("The %s address is beyond the %s addresses in the %s/%s "
"network."%(numify(int(options.lookFor)),size,network,bits))```