Skip to content

Instantly share code, notes, and snippets.

@kaugm
Last active April 18, 2022 11:35
Show Gist options
  • Save kaugm/24ac773e6eebf663a0b099f32200684f to your computer and use it in GitHub Desktop.
Save kaugm/24ac773e6eebf663a0b099f32200684f to your computer and use it in GitHub Desktop.
IP Address class for use in Python scripts
import re
'''IP Address Class'''
class Address:
# Clean up user input and split into ip and mask
# Accepted input format -> '192.168.1.4/24'
def __init__(self, address):
regex = "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d+$"
if len(re.findall(regex, address)) == 1:
ipstr,cidrstr = address.split('/')
self._addr = ipstr.split('.')
self._cidr = int(cidrstr)
else:
raise TypeError('No valid IP address found in input. Please use format X.X.X.X/XX')
# Cleaning up IP address
@property
def address(self):
return '.'.join(map(str, self._addr))
# For each bit in each octet (8 times), add a decreasing power of 2 to the octet (128,64,32,..)
# Repeated 8 times = 255, repeated <8 times gives the final octet
@property
def mask(self):
mask = [0 for x in range(4)]
for i in range(self._cidr):
mask[int(i/8)] = mask[int(i/8)] + (1 << (7 - i % 8))
return '.'.join(map(str, mask))
# Updating subnet mask in format: X.X.X.X
# Update Address.mask and Address._cidr by counting '1' in binary conversion of number
@mask.setter
def mask(self, new_mask):
mask = new_mask.split('.')
self._cidr = sum([bin(int(octet)).count('1') for octet in new_mask.split('.')])
# Network address from ANDing IP address and subnet mask
@property
def network(self):
net = [int(self._addr[i]) & int(self.mask.split('.')[i]) for i in range(4)]
return '.'.join(map(str, net))
# Wildcard mask from XORing 255 with each octect of subnet mask
# Then add wildcard mask to Network address to get broadcast address
@property
def broadcast(self):
xor = [int(self.mask.split('.')[i]) ^ 255 for i in range(4)]
broadcast = [int(self.network.split('.')[i]) + xor[i] for i in range(4)]
return '.'.join(map(str, broadcast))
# Network addresses are always even -> Last bit is always 0. Simply add 1 to this to get the first address
@property
def first(self):
first = [int(octet) for octet in self.network.split('.')]
first[3] = first[3] ^ 1
return '.'.join(map(str, first))
# Last usable address, start at first host bit of network address and flip bits to 1
# Then AND last octet by 254
@property
def last(self):
last = [int(octet) for octet in self.network.split('.')]
for i in range(32 - self._cidr):
last[int((self._cidr + i) / 8)] = last[int((self._cidr + i) / 8)] + (1 << (i % 8))
last[3] = last[3] & 254
return '.'.join(map(str, last))
# Check to see if IP is in range: Network bits match
# Expected usage: <string like 192.168.1.45> in Address
def __contains__(self, addr):
new = addr.split('.')
net = [int(self._addr[i]) & int(self.mask.split('.')[i]) for i in range(4)]
new_net = [int(new[i]) & int(self.mask.split('.')[i]) for i in range(4)]
for i in range(4):
if int(net[i]) != int(new_net[i]):
return False
return True
# Print all information
def get_all(self):
print(f'''
IP Address: {self.address}
Subnet Mask: {self.mask}
Network Address: {self.network}
First Usable: {self.first}
Last Usable: {self.last}
Broadcast Address: {self.broadcast}
''')
# Return IP address
def __str__(self):
return self.address
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment