from .net_cidr_is_cidr import cidr_block from .net_ipv4_parse_ipv4 import ipv4_value from .net_ipv6_parse_ipv6 import ipv6_groups def cidr_contains(cidr: str, address: str) -> bool: """Whether an address lies inside a block, IPv4 or IPv6. An address of the other family is never inside (an IPv4-mapped IPv6 address is not treated as its IPv4 address). """ block = cidr_block(cidr) if block is None: raise ValueError('"%s" is not a CIDR block' % (cidr,)) v4 = ipv4_value(address) v6 = ipv6_groups(address) if v4 is None else None if v4 is None and v6 is None: raise ValueError('"%s" is not an IP address' % (address,)) if block.version == 4: if v4 is None: return False size = 2 ** (32 - block.prefix) return v4 // size == block.bits[0] // size if v6 is None: return False for i in range(8): bits = max(0, min(16, block.prefix - 16 * i)) size = 2 ** (16 - bits) if v6[i] // size != block.bits[i] // size: return False return True