Last active
May 17, 2017 09:36
-
-
Save mepcotterell/5044319 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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