Last active
November 11, 2020 16:45
-
-
Save AMMullan/ee9a3d7a38de703ff437765ebd0fc38e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
import socket | |
import struct | |
import platform | |
try: | |
import ipaddress | |
except: | |
raise SystemExit('Script can only execute in Python 3.3 or newer.') | |
def print_usage(msg=None): | |
print('''%sUsage: ipcalc.py <ADDRESS>[[/]<NETMASK>] [NETMASK] | |
This is a rewrite to Python of the ipcalc util (http://jodies.de/ipcalc). | |
Trying to keep Python native. | |
ipcalc takes an IP address and netmask and calculates the resulting broadcast, | |
network, Cisco wildcard mask, and host range. By giving a second netmask, you | |
can design sub- and supernetworks. It is also intended to be a teaching tool | |
and presents the results as easy-to-understand binary values. | |
Examples: | |
ipcalc 192.168.0.1/24 | |
ipcalc 192.168.0.1/255.255.128.0 | |
ipcalc 192.168.0.1 255.255.128.0 255.255.192.0 | |
ipcalc 192.168.0.1 0.0.63.255''' % (msg + '\n\n' if msg else '')) | |
raise SystemExit | |
def handle_args(args): | |
cidr = None | |
netmask = None | |
netmask_new = None | |
if not args[1:]: | |
print_usage() | |
if '-h' in args: | |
print_usage() | |
is_aws = False | |
if '-a' in args: | |
is_aws = True | |
args.remove('-a') | |
try: | |
network = ipaddress.ip_network(args[1], strict=True) | |
except ValueError: | |
print_usage('Invalid CIDR Provided') | |
else: | |
cidr = network.network_address | |
netmask = network.prefixlen | |
if args[2:]: | |
if args[2].isdigit(): | |
netmask_new = int(args[2]) | |
else: | |
netmask_new = ip_to_bin(args[2]).count('1') | |
if netmask_new <= netmask: | |
print_usage('New prefix must be longer than original.') | |
return [str(cidr), netmask, netmask_new, is_aws] | |
def ip_to_bin(ip_addr): | |
return '.'.join([bin(int(x) + 256)[3:] for x in ip_addr.split('.')]) | |
def prefix_to_netmask(prefix): | |
return socket.inet_ntoa(struct.pack(">I", (0xffffffff << (32 - prefix)) & 0xffffffff)) | |
def get_network_ips(network): | |
sub = ipaddress.ip_network(network) | |
return [str(host) for host in list(sub.hosts())] | |
def get_network_subnets(network, new_prefix): | |
sub = ipaddress.ip_network(network) | |
if new_prefix: | |
return [str(subnet) for subnet in sub.subnets(new_prefix=new_prefix)] | |
return [network] | |
def print_line(title, address, binary="", comment=""): | |
print( | |
'%-20s%-22s%-36s%s' % ( | |
title, | |
address, | |
binary, | |
comment | |
) | |
) | |
def main(cidr, subnet, output_to=None, is_aws=False): | |
network = '%s/%s' % (cidr, subnet) | |
aws = {} | |
sub_count = addr_count = 0 | |
for network_subnet in get_network_subnets(network, output_to): | |
address, prefix = network_subnet.split('/') | |
netmask = prefix_to_netmask(int(prefix)) | |
subnet_hosts = get_network_ips(network_subnet) | |
if subnet_hosts: | |
if is_aws: | |
aws['router'] = subnet_hosts[0] | |
aws['dns'] = subnet_hosts[1] | |
aws['fu'] = subnet_hosts[2] | |
first_host = subnet_hosts[3] | |
else: | |
first_host = subnet_hosts[0] | |
last_host = subnet_hosts[-1] | |
# /32 network | |
else: | |
subnet_hosts = [network_subnet] | |
first_host = last_host = cidr | |
host_count = len(subnet_hosts) - len(aws.keys()) | |
sub_count += 1 | |
addr_count += host_count | |
print_line('Address:', address, ip_to_bin(address)) | |
print_line('Netmask:', '%s = %d' % (netmask, int(prefix)), ip_to_bin(netmask)) | |
print_line('Network:', network_subnet, ip_to_bin(cidr)) | |
if is_aws: | |
print_line('- AWS Router:', aws['router'], ip_to_bin(aws['router'])) | |
print_line('- AWS DNS:', aws['dns'], ip_to_bin(aws['dns'])) | |
print_line('- AWS Future Use:', aws['fu'], ip_to_bin(aws['fu'])) | |
print_line('- First Host:', first_host, ip_to_bin(first_host)) | |
print_line('- Last Host:', last_host, ip_to_bin(last_host)) | |
print_line('- Host Count:', host_count) | |
print('') | |
if sub_count: | |
print('=====\nSubnets: %d' % sub_count) | |
print('Address Count: %d' % addr_count) | |
if __name__ == "__main__": | |
if not platform.python_version().startswith('3.'): | |
raise SystemExit('Python 3.3 or newer required.') | |
CIDR, NETMASK, NETMASK_NEW, IS_AWS = handle_args(sys.argv) | |
main(CIDR, NETMASK, NETMASK_NEW, IS_AWS) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment