""" Identifier Class for localsubnet """ import ipaddress import netifaces import re def data_is_valid(data): """Check to see if data is valid for this class. Returns a tuple of (bool, string) indicating valididty and any error message. """ if type(data) == dict and len(data) == 0: return True, None return False, "Data is not an object or not empty." # These are for ue by ipv6_netmask_size() ipv6_netmask_re = re.compile("^([f]*)([ec80]?)0*$") ipv6_digit_bits = { "e": 3, "c": 2, "8": 1, "0": 0, "": 0 } def ipv6_netmask_size(mask_in): """ Convert an IPv6 netmask (e.g., ffff:ffff::) to a prefix size (32). """ mask = mask_in.lower() # Lead-pad any parts with less than four digits parts = [ '0' * (4-len(part)) + part for part in mask.split(":") ] mask = "".join(parts) matches = ipv6_netmask_re.search(mask) if matches is None: raise ValueError("Invalid IPv6 netmask '%s'" % (mask_in)) bits = len(matches.group(1)) * 4 last = matches.group(2) if last is not None: bits += ipv6_digit_bits[last] return bits class IdentifierLocalSubnet(): """ Class that holds and processes identifiers """ def __init__(self, data # Data suitable for this class ): valid, message = data_is_valid(data) if not valid: raise ValueError("Invalid data: %s" % message) self.cidrs = [] for iface in netifaces.interfaces(): ifaddrs = netifaces.ifaddresses(iface) pairs = [] for ifaddr in ifaddrs[netifaces.AF_INET] \ if netifaces.AF_INET in ifaddrs else []: self.cidrs.append(ipaddress.IPv4Network( unicode("%s/%s" % (ifaddr["addr"], ifaddr["netmask"])), strict=False # Don't complain about host bits being set. )) for ifaddr in ifaddrs[netifaces.AF_INET6] \ if netifaces.AF_INET6 in ifaddrs else []: self.cidrs.append(ipaddress.IPv6Network( unicode("%s/%s" % ( ifaddr["addr"].split("%")[0], ipv6_netmask_size(ifaddr["netmask"]))), strict=False # Don't complain about host bits being set. )) def evaluate(self, hints # Information used for doing identification ): """Given a set of hints, evaluate this identifier and return True if an identification is made. """ try: ip = ipaddress.ip_network(unicode(hints["requester"])) except KeyError: return False for cidr in self.cidrs: if cidr.overlaps(ip): return True return False # A short test program if __name__ == "__main__": ident = IdentifierLocalSubnet({}) for ip in [ "127.0.0.1", "::1", "10.1.1.1", "198.129.254.30", "dead:beef::1", "10.0.2.12" ]: print ip, ident.evaluate({ "requester": ip })