First upload

This commit is contained in:
Marco Cetica 2023-11-11 16:20:22 +01:00
commit 342abbd643
Signed by: marco
GPG Key ID: 45060A949E90D0FD
3 changed files with 147 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Marco
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

20
README.md Normal file
View File

@ -0,0 +1,20 @@
# subnet.py
CLI tool to determine various information of a given IPv4 address in CIDR format.
## Installation
This program is written in Python using only the builtin libraries, you can move it
wherever you like and invoke it from there.
## Usage
Run the program without any parameter, the helper will walk you through on how to use it.
For example:
```sh
$> ./subnet.py 10.0.3.4/24
IP Address: 10.0.3.4 (00001010 00000000 00000011 00000100)
Subnet Mask: 255.255.255.0 (11111111 11111111 11111111 00000000)
Network Prefix: 10.0.3.0 (00001010 00000000 00000011 00000000)
Host Prefix: 0.0.0.4 (00000000 00000000 00000000 00000100)
Usable Hosts: 254
IP Class: A
```

106
subnet.py Executable file
View File

@ -0,0 +1,106 @@
#!/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 = ""
ip_class: 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
# Get IP Class
first_octet = int(self.ip_addr.split('.')[0])
ip_classes = {
(0 < first_octet <= 127): 'A',
(128 <= first_octet <= 191): 'B',
(192 <= first_octet <= 223): 'C'
}
self.ip_class = next((val for cond, val in ip_classes.items() if cond), None)
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}")
print(f"IP Class: {ip.ip_class}")
except ValueError as e:
print(e)
sys.exit(1)
if __name__ == "__main__":
main()