If you are engaged in NetDevOps, you need to validate and convert data, and occasionally, you’ll require some assistance. Here is a small collection of tools that will be expanded periodically.
Validators#
Check if IP is in CIDR#
import ipaddress
def check_ip_in_cidr(ip, cidr):
ip_address = ipaddress.IPv4Address(ip)
network = ipaddress.IPv4Network(cidr, strict=False)
return ip_address in network
Check valid CIDR#
import re
def is_valid_cidr(cidr):
# CIDR Format: IP/Prefix, e.g., 192.168.0.1/24
cidr_regex = re.compile(r'^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$')
if not cidr_regex.match(cidr):
return False
# Split the CIDR into IP and prefix
ip, prefix = cidr.split('/')
# Check if prefix is in the range 0-32
if not (0 <= int(prefix) <= 32):
return False
# Check if each part of the IP is in the range 0-255
ip_parts = ip.split('.')
for part in ip_parts:
if not (0 <= int(part) <= 255):
return False
return True
Validate correct hostname#
import re
def is_valid_hostname(hostname):
if len(hostname) > 255:
return False
if hostname[-1] == ".":
hostname = hostname[:-1] # strip exactly one dot from the right, if present
allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
return all(allowed.match(x) for x in hostname.split("."))
Check valid value ip or hostname#
import socket
def check_valid_value(value):
""" Validate if value is correct. """
try:
# CASE 1
socket.inet_aton(value)
return value
except socket.error:
if is_valid_hostname(value) is False:
raise ValueError("IP or Hostname not valid.")
else:
return value
Converters#
Hex to IP converter#
import struct
import socket
def hex2ip(hex_ip):
addr_long = int(hex_ip,16)
hex(addr_long)
hex_ip = socket.inet_ntoa(struct.pack(">L", addr_long))
return hex_ip
IP range to CIDR converter#
import ipaddress
def ip_range_to_cidr(start_ip, end_ip):
try:
start = ipaddress.ip_address(start_ip)
end = ipaddress.ip_address(end_ip)
if start.version != end.version:
raise ValueError("start and end ip are not same ip version.")
start_int = int(start)
end_int = int(end)
if start_int > end_int:
raise ValueError("start ip must be smaller that end ip.")
networks = list(ipaddress.summarize_address_range(start, end))
for network in networks:
if network.network_address == start and network.broadcast_address == end:
return str(network)
raise ValueError("no matching cidr.")
except ValueError as e:
return str(e)
IP to Long#
import socket
import struct
def ip2long(ip):
"""
Convert an IP string to long
"""
packedIP = socket.inet_aton(ip)
return struct.unpack("!L", packedIP)[0]
Long to IP#
import socket
import struct
def long2ip(long):
"""
Convert long to IP string
"""
return socket.inet_ntoa(struct.pack('!L', long))
Formatters#
MAC address formatter#
def format_mac(mac: str) -> str:
""" Convert any MAC format to uniform xx:xx:xx:xx:xx:xx format """
mac = re.sub('[.:-]', '', mac).lower() # remove delimiters and convert to lower case
mac = ''.join(mac.split()) # remove whitespaces
assert len(mac) == 12 # length should be now exactly 12 (eg. 008041aefd7e)
assert mac.isalnum() # should only contain letters and numbers
# convert mac in canonical form (eg. 00:80:41:ae:fd:7e)
mac = ":".join(["%s" % (mac[i:i+2]) for i in range(0, 12, 2)])
return mac
Helpers#
Get first ip of subnet#
import ipaddress
def get_first_ip(cidr):
return str(ipaddress.IPv4Network(cidr, strict=False)[0])
Get last ip of subnet#
import ipaddress
def get_last_ip(cidr):
return str(ipaddress.IPv4Network(cidr, strict=False)[-1])
Progressbar#
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = 'â–ˆ', printEnd = "\r"):
"""
Call in a loop to create terminal progress bar
@params:
iteration - Required : current iteration (Int)
total - Required : total iterations (Int)
prefix - Optional : prefix string (Str)
suffix - Optional : suffix string (Str)
decimals - Optional : positive number of decimals in percent complete (Int)
length - Optional : character length of bar (Int)
fill - Optional : bar fill character (Str)
printEnd - Optional : end character (e.g. "\r", "\r\n") (Str)
"""
percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filledLength = int(length * iteration // total)
bar = fill * filledLength + '-' * (length - filledLength)
print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)
# Print New Line on Complete
if iteration == total:
print()
Get from CIDR host adress CIDR network#
import ipaddress
def get_cidr_network(ip_cidr):
return str(ipaddress.ip_network(ip_cidr, strict=False))
Get from IP and netmask the CIDR netmask#
import ipaddress
def calculate_cidr(ip, netmask):
try:
# Convert IP and netmask to ipaddress objects
ip_obj = ipaddress.IPv4Address(ip)
netmask_obj = ipaddress.IPv4Network(f"0.0.0.0/{netmask}").netmask
# Calculate network address
network_address = ipaddress.IPv4Network(f"{ip}/{netmask}", strict=False).network_address
# Calculate prefix length
prefix_length = ipaddress.IPv4Network(f"0.0.0.0/{netmask}").prefixlen
# Return CIDR notation
return f"{network_address}/{prefix_length}"
except ValueError as e:
return str(e)
Compress list of CIDR networks to reduce overhead#
import sys
from netaddr import cidr_merge
def main(FILE):
with open(FILE) as f:
raw_lines = f.readlines()
subnets = []
for line in raw_lines:
subnets.append(line.strip())
subnets = cidr_merge(subnets)
for subnet in subnets:
print(subnet)
if __name__ == "__main__":
main(sys.argv[1])