Skip to content

Instantly share code, notes, and snippets.

@mepcotterell
Last active May 17, 2017 09:36
Show Gist options
  • Save mepcotterell/5044319 to your computer and use it in GitHub Desktop.
Save mepcotterell/5044319 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
'''
subnet -- phatty tools for dealing with subnets
@author: Michael E. Cotterell <[email protected]>
'''
import struct
import sys
import os
def subnet_mask(bits = 24):
"""
Return a subnet mask IP (tuple of four 1 byte numbers) that uses the number of bits
specified.
"""
# check bits
if bits < 0 or bits > 32:
raise Exception("Invalid bit count!")
# get the raw mask
# the following will create a number represented as bits-many 1 digits in binary.
# it then takes those bits and shifts them to the left so that they are aligned
# to the left of a 4 byte boundary
rawmask = ((1 << bits) - 1) << (32 - bits)
# get the mask
mask = struct.pack("!L", rawmask) # convert the 4 byte number into four bytes
mask = struct.unpack("!BBBB", mask) # convert the four bytes into four 1 byte numbers
# return the tuple of four 1 byte numbers as the mask
return mask
def subnet_info(ip = (192, 128, 0, 0), mask = 24):
"""
Returns subnet information for the IP address and mask given
"""
# get ip as a 32 bit number
try:
rawip = struct.pack("!BBBB", ip[0], ip[1], ip[2], ip[3]) # pack four 1 byte numbers into four bytes
rawip = struct.unpack("!L", rawip)[0] # unpack those four bytes into one 4 byte number
except:
raise Exception("Invalid IP address")
# check the mask bits
if mask < 0 or mask > 32:
raise Exception("Invalid mask bit count!")
# get the raw mask
# the following will create a number represented as bits-many 1 digits in binary.
# it then takes those bits and shifts them to the left so that they are aligned
# to the left of a 4 byte boundary
rawmask = ((1 << mask) - 1) << (32 - mask)
# build network id
rawnetwork = rawip & rawmask # only keep the first mask-many bits in the ip
network = struct.pack("!L", rawnetwork) # convert the one 4 byte number to four bytes
network = struct.unpack("!BBBB", network) # convert the four bytes to four 1 byte numbers
# lower bound
rawlower = rawnetwork # the lower bound is the network number
lower = struct.pack("!L", rawlower) # convert the one 4 byte number to four bytes
lower = struct.unpack("!BBBB", lower) # convert the four bytes to four 1 byte numbers
# upper bound
rawupper = rawnetwork + (1 << (32 - mask)) - 1 # upper bound is the network with last (32 - mask) bits as all 1's in binary
upper = struct.pack("!L", rawupper) # convert the one 4 byte number to four bytes
upper = struct.unpack("!BBBB", upper) # convert the four bytes to four 1 byte numbers
# return ((network, mask), lower, upper)
return (((network[0], network[1], network[2], network[3]), mask), (lower[0], lower[1], lower[2], lower[3]), (upper[0], upper[1], upper[2], upper[3]))
def subnet_info_from_range(lower = (192, 168, 0, 0), upper = (192, 168, 0, 255)):
"""
Returns information on the maximally masked subnet for the IP range
provided. In many cases, the range that is returned will be wider than the
input.
"""
# determine raw lower ip
try:
rawlower = struct.pack("!BBBB", lower[0], lower[1], lower[2], lower[3]) # convert the four 1 byte numbers into four bytes
rawlower = struct.unpack("!L", rawlower)[0] # convert the four bytes into one 4 byte number
except:
raise Exception('Invalid lower bound IP address')
# determine raw upper ip
try:
rawupper = struct.pack("!BBBB", upper[0], upper[1], upper[2], upper[3]) # convert the four 1 byte numbers into four bytes
rawupper = struct.unpack("!L", rawupper)[0] # convert the four bytes into one 4 byte number
except:
raise Exception('Invalid upper bound IP address')
# compare the bounds
# the lower bound must be smaller than the upper bound
if rawlower >= rawupper:
raise Exception('Invalid IP range.')
# build the mask by comparing the bits
# from left to right, increase the number up bits until the lower and
# upper bound are different
mask = 0
while (rawlower & (1 << (31 - mask)) == rawupper & (1 << (31 - mask))):
mask += 1
# get the raw mask
# the following will create a number represented as bits-many 1 digits in binary.
# it then takes those bits and shifts them to the left so that they are aligned
# to the left of a 4 byte boundary
rawmask = ((1 << mask) - 1) << (32 - mask)
# determine the network
rawnetwork = rawlower & rawmask # get the network by applying the mask to the lower bound
network = struct.pack("!L", rawnetwork) # convert the one 4 byte number to four bytes
network = struct.unpack("!BBBB", network) # convert the four bytes to four 1 byte numbers
# return info for (network, mask)
return subnet_info((network[0], network[1], network[2], network[3]), mask)
def main(argv=None): # IGNORE:C0111
if argv is None:
argv = sys.argv
else:
sys.argv.extend(argv)
# stuff
info = subnet_info((192, 168, 0, 34), 24)
print('{}\n'.format(info))
info = subnet_info((192,168,3,4), 20)
print('{}\n'.format(info))
info = subnet_info((192,168,0,0), 18)
print('{}\n'.format(info))
info = subnet_info_from_range((192,168,0,4), (192,168,255,5))
print('{}\n'.format(info))
print('{}\n'.format(subnet_mask(18)))
if __name__ == "__main__":
sys.exit(main())
#!/usr/bin/env python3
def subnet_info(ip = (192, 128, 0, 0), mask = 24):
"""
Returns subnet information for the IP address and mask given
"""
# get ip as a 32 bit number
try:
rawip = struct.pack("!BBBB", ip[0], ip[1], ip[2], ip[3]) # pack four 1 byte numbers into four bytes
rawip = struct.unpack("!L", rawip)[0] # unpack those four bytes into one 4 byte number
except:
raise Exception("Invalid IP address")
# check the mask bits
if mask < 0 or mask > 32:
raise Exception("Invalid mask bit count!")
# get the raw mask
# the following will create a number represented as bits-many 1 digits in binary.
# it then takes those bits and shifts them to the left so that they are aligned
# to the left of a 4 byte boundary
rawmask = ((1 << mask) - 1) << (32 - mask)
# build network id
rawnetwork = rawip & rawmask # only keep the first mask-many bits in the ip
network = struct.pack("!L", rawnetwork) # convert the one 4 byte number to four bytes
network = struct.unpack("!BBBB", network) # convert the four bytes to four 1 byte numbers
# lower bound
rawlower = rawnetwork # the lower bound is the network number
lower = struct.pack("!L", rawlower) # convert the one 4 byte number to four bytes
lower = struct.unpack("!BBBB", lower) # convert the four bytes to four 1 byte numbers
# upper bound
rawupper = rawnetwork + (1 << (32 - mask)) - 1 # upper bound is the network with last (32 - mask) bits as all 1's in binary
upper = struct.pack("!L", rawupper) # convert the one 4 byte number to four bytes
upper = struct.unpack("!BBBB", upper) # convert the four bytes to four 1 byte numbers
# return ((network, mask), lower, upper)
return (((network[0], network[1], network[2], network[3]), mask), (lower[0], lower[1], lower[2], lower[3]), (upper[0], upper[1], upper[2], upper[3]))
def main(argv=None): # IGNORE:C0111
info = subnet_info((192, 168, 0, 34), 24)
print('{}\n'.format(info))
info = subnet_info((192,168,3,4), 20)
print('{}\n'.format(info))
if __name__ == "__main__":
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment