95 lines
3.2 KiB
Python
Executable File
95 lines
3.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# CLI tool to determine various information
|
|
# of a given IPv4 address in CIDR format
|
|
# Developed by Marco Cetica (c) 2023 <email@marcocetica.com>
|
|
#
|
|
import sys
|
|
import ipaddress
|
|
|
|
class IP:
|
|
"""Extract various information from an IPv4 in CIDR format"""
|
|
cidr: str = ""
|
|
ip_addr: str = ""
|
|
mask: str = ""
|
|
mask_bin: str = ""
|
|
network_prefix: str = ""
|
|
network_bin: str = ""
|
|
host_prefix: str = ""
|
|
host_bin: str = ""
|
|
usable_hosts: str = ""
|
|
|
|
def __init__(self, cidr):
|
|
# Check if CIDR is properly formatted
|
|
if '/' not in cidr:
|
|
raise ValueError("Invalid CIDR('xxx.xxx.xxx.xxx/xx')")
|
|
|
|
# Check if IP address is valid
|
|
ip_addr, mask = cidr.split('/')
|
|
octets = ip_addr.split('.')
|
|
if len(octets) != 4:
|
|
raise ValueError("Invalid IP address")
|
|
|
|
for v in octets:
|
|
if int(v) > 255 or int(v) < 0:
|
|
raise ValueError("IP address out of range")
|
|
|
|
# Check if subnet mask is in range
|
|
if int(mask) > 32 or int(mask) < 1:
|
|
raise ValueError("Subnet mask out of range")
|
|
|
|
# Otherwise set cidr
|
|
self.cidr = cidr
|
|
|
|
def extract_data(self) -> None:
|
|
# Get IP and subnet mask
|
|
self.ip_addr = self.cidr.split('/')[0]
|
|
self.mask = ipaddress.IPv4Network(self.cidr, strict=False).netmask
|
|
|
|
# Convert both of them to int
|
|
network = ipaddress.IPv4Network(self.ip_addr)
|
|
ip_addr_int = int(network.network_address)
|
|
mask_int = int(self.mask)
|
|
|
|
# Get network and host prefix
|
|
network_prefix_int = (ip_addr_int & mask_int)
|
|
host_prefix_int = (ip_addr_int & ~mask_int)
|
|
|
|
# Convert network and host prefix back to dot notation
|
|
self.network_prefix = str(ipaddress.IPv4Network(network_prefix_int)).split('/')[0]
|
|
self.host_prefix = str(ipaddress.IPv4Network(int(host_prefix_int))).split('/')[0]
|
|
|
|
# Get binary representation of ip address, mask and prefixes
|
|
self.ip_bin = ' '.join(format(int(x), '08b') for x in self.ip_addr.split('.'))
|
|
self.mask_bin = ' '.join(format(int(x), '08b') for x in str(self.mask).split('.'))
|
|
self.network_bin = ' '.join(format(int(x), '08b') for x in self.network_prefix.split('.'))
|
|
self.host_bin = ' '.join(format(int(x), '08b') for x in self.host_prefix.split('.'))
|
|
|
|
# Compute usable hosts
|
|
mask_complement = (~mask_int & (2 ** mask_int.bit_length() - 1))
|
|
bit_count = bin(mask_complement).count('1')
|
|
self.usable_hosts = (2 ** bit_count - 2) if bit_count > 0 else 0
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print(f"Usage {sys.argv[0]} <CIDR>")
|
|
sys.exit(1)
|
|
|
|
# Get the CIRD
|
|
cidr = sys.argv[1]
|
|
|
|
# Extract info from IP
|
|
try:
|
|
ip = IP(cidr)
|
|
ip.extract_data()
|
|
print(f"IP Address: {ip.ip_addr} ({ip.ip_bin})")
|
|
print(f"Subnet Mask: {ip.mask} ({ip.mask_bin})")
|
|
print(f"Network Prefix: {ip.network_prefix} ({ip.network_bin})")
|
|
print(f"Host Prefix: {ip.host_prefix} ({ip.host_bin})")
|
|
print(f"Usable Hosts: {ip.usable_hosts}")
|
|
except ValueError as e:
|
|
print(e)
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|