from .net_cidr_is_cidr import cidr_block from .net_cidr_types import CidrInfo from .net_ipv4_format_ipv4 import format_ipv4 def cidr_info(cidr: str) -> CidrInfo: """Everything a subnet calculator shows for one IPv4 block. Host bits in the input are dropped (192.168.1.77/24 describes 192.168.1.0/24). A /31 is a point-to-point link with two usable addresses and no broadcast (RFC 3021); a /32 is one host. """ block = cidr_block(cidr) if block is None: raise ValueError('"%s" is not a CIDR block' % (cidr,)) if block.version != 4: raise ValueError('cidrInfo handles IPv4 blocks only, received "%s"' % (cidr,)) prefix = block.prefix size = 2 ** (32 - prefix) network = block.bits[0] - block.bits[0] % size last = network + size - 1 point_to_point = prefix >= 31 return CidrInfo( cidr="%s/%d" % (format_ipv4(network), prefix), network=format_ipv4(network), prefix=prefix, netmask=format_ipv4(4294967296 - size), wildcard=format_ipv4(size - 1), broadcast=None if point_to_point else format_ipv4(last), first_host=format_ipv4(network if point_to_point else network + 1), last_host=format_ipv4(last if point_to_point else last - 1), host_count=size if point_to_point else size - 2, address_count=size, )