SubnetExerciseGenerator/main.py
2023-09-27 10:00:36 +02:00

158 lines
6.0 KiB
Python

import math
import random
print("Made by VitaAeterna and NekoSilvertail https://github.com/VitaAetaerna/SubnetExerciseGenerator/")
def intToDotted(ip):
# input: ip
# determins dotted decimal format for given ip as int
# returns list octets
octets = []
while ip != 0:
octets.append(ip % 256)
ip = math.floor(ip / 256)
octets.reverse()
return octets
def printDotted(ip):
# input: ip as integer
# returns the dotted decimal format
# hint: use '.'.join()
# returns prettyfied dotted decimal format as string
octets = intToDotted(ip)
return ".".join(str(x) for x in octets)
def generateNetwork():
# input: none
# generates a random ip and prefix
# the generated prefix should be in the range [8, 29]
# to avoid getting too large and too small networks
# returns dict: {"ip":ip, "prefix":prefix}
ip = random.randint(0, 2**32-1)
prefix = random.randint(8, 29) #max prefix generated is
# 29, allowing for at least 1 bit to be subnetted and still have valid hosts left
ipandprefix = {"ip":ip, "prefix":prefix}
return ipandprefix
def analyseSubnet(ip, prefix):
# input: ip as int, prefix as int
# returns net id, broadcast address
# returns dict: {"nid":netid, "bc":bc}
snm=(2**prefix-1)<<(32-prefix)
netid = ip&snm
wmask = 0xffffffff >> prefix
bc = ip|wmask
return {"nid":netid, "bc":bc}
def newSubnetExercises(ip, prefix):
# input: a subnet, consisting of an ip
# and a given prefix
# generates a new subnet exercise
# 1. determine the type of exercise
# types: split into x subnets
# split into subnets with x hosts
# 2. print out the given subnet
# 3. determine if there is optional exercises
# like determining a specific subnet (start, end), etc
# think of new types of exercises to add into this
# output logic
# 4. print out the exercise:
# "split the given network into...."
# depending on the type of exercise
# returns dict: {"ip":ip, "prefix":prefix, "newprefix":newprefix}
# newprefix contains the new subnet mask that solves the exercise
nid = analyseSubnet(ip, prefix).get("nid")
newprefix = random.randint(prefix+1, 30) # max 30 to leave 2 hostbits (no empty nets)
listnetwork = -1 #set this to -1, meaning "exercise did not appear"
print("Exercise:\n")
print("Given Network: {}/{}\n".format(printDotted(nid), prefix))
# sanity assertions
assert(prefix<newprefix) #no supernetting, only subnetting, at least 1 bit difference
# (otherwise no subnets!)
assert(32-newprefix > 1) #must allow for more than 1 hostbit (no usable hosts otherwise)
if random.random() > 0.5:
#ask user to split into networks, but make sure the amount of networks
#requires to use the specific prefix generated by the exercise
#start is set to at least as much subnets as 1 bit less, but plus one so
#you cannot use one fewer bits for the new prefix
#end is set to exactly the amount of subnets possible with the newprefix
print("Split the Network into {} subnets".format(random.randint(2**(newprefix-prefix-1)+1,2**(newprefix-prefix))))
else:
#ask user to split into hosts, but make sure the amount of hosts required
#requires the user to use at least the new prefix generated
#-1 at the start means it's at least enough hosts as 1 hostbit less
# -> since 2 hosts are left, using 1 less hostbit is not allowed
#-2 at the end makes sure the required amount of hosts still fit
# within the specific new prefix
print("Split the network into subnets with {} Hosts".format(random.randint(2**(32-newprefix-1),2**(32-newprefix)-2)))
if random.random() > 0.5:
listnetwork = random.randint(0, 2^(newprefix-prefix)-1) # user may list this network
#make the user list a specific network between 0 and the last
print("\nList the start and end of Subnet {}".format(listnetwork))
return {"ip":ip, "prefix":prefix, "newprefix":newprefix, "listnetwork":listnetwork}
def listSubnets(ip, prefix, newprefix):
# input: a network range and a subnet prefix, a new prefix for subnetting
# note: sanity check with: assert newprefix > prefix
# this function prints out every possible network
# within the given range, showing net id and bc
# as well as amount of adresses and usable hosts per network
# returns: nothing, this just prints all possible subnets
hostbits = 32-newprefix
newnets = 2**(newprefix-prefix)
nid = analyseSubnet(ip, prefix).get("nid")
for i in range(0,newnets):
print("Network", i,":", printDotted(nid+i*2**hostbits))
if i > 8:
#-10 -> we list network 0 to 9 (larger than 8), which is 10 already listed
print("and {} more...".format(newnets-10))
break
if __name__ == '__main__':
# 1. Generate new exercise
# 2. wait for user input, noting that the solution
# will be shown after after pressing any key
# 3. print the solution
# 4. exit
network = generateNetwork()
ip = network.get("ip")
prefix = network.get("prefix")
net = analyseSubnet(ip, prefix)
exercise = newSubnetExercises(ip=ip, prefix=prefix)
newprefix = exercise.get("newprefix")
listnetwork = exercise.get("listnetwork")
#wait for an enter to continue
input("\nPress Enter to show solution\n")
print("The original network starts at {} and ends at {}.".format(printDotted(net.get("nid")), printDotted(net.get("bc"))))
print("The new prefix is {}, allowing for {} subnets with {} Hosts each".format(newprefix, 2**(newprefix-prefix), 2**(32-newprefix)-2))
if(listnetwork >= 0):
subnet=analyseSubnet(net.get("nid")+listnetwork*2**(32-newprefix), newprefix)
print("Network {}: NID: {} BC: {}".format(listnetwork, printDotted(subnet.get("nid")), printDotted(subnet.get("bc"))))
print("\nSubnets:")
listSubnets(ip, prefix, newprefix)
input("\nPress enter to exit\n")