def ipv4_from_macaddr(macaddr): """ Given @macaddr, returns the @ipv4 or None if unknown / lookup failed, etc. """ if not is_mac_address_valid(macaddr): return None macaddr = normalize_mac_address(macaddr).lower() by_macaddr = load(DHCPD_LEASES_FILENAME)[1] if macaddr not in by_macaddr: return None else: return by_macaddr[macaddr].ipv4
def load(filename): """ Load a dhcpd.leases file. WARNING: The parsing is _NOT_ done the same way dhcpd does it, for simplicity reasons. Anyway it should work. Maybe. Returns (by_ipv4, by_macaddr) where both are dictionaries in which values are LeaseEntry instances and keys are IPv4 in @by_ipv4 and mac address in @by_macaddr. TODO: check validity periods """ by_ipv4 = {} by_macaddr = {} state = NOWHERE for line in file(filename): line = line.rstrip() fully_stripped_line = line.lstrip() if (not fully_stripped_line) or fully_stripped_line[0] == '#': continue if state is NOWHERE: if line.startswith("lease "): lease_header = line.split() if len(lease_header) == 3 and is_ipv4_address_valid(lease_header[1]) and lease_header[2] == "{": current = LeaseEntry(lease_header[1]) state = LEASE else: # XXX log that our parser is too dumb to correctly parse the file state = UNKNOWN elif state is UNKNOWN: if fully_stripped_line == '}': state = NOWHERE else: pass # XXX log elif state is LEASE: for start, method in LEASE_ATTRS: remain = match_remain_and_strip_semicolon(fully_stripped_line, start) if remain is not None: method(current, remain) break else: if fully_stripped_line == '}': if current.ipv4 in by_ipv4: macaddr_to_rm = by_ipv4[current.ipv4].macaddr del by_ipv4[current.ipv4] del by_macaddr[macaddr_to_rm] if is_mac_address_valid(getattr(current, 'macaddr', "")) \ and getattr(current, 'binding_state', None) == 'active': if current.macaddr in by_macaddr: ipv4_to_rm = by_macaddr[current.macaddr].ipv4 del by_ipv4[ipv4_to_rm] del by_macaddr[current.macaddr] by_ipv4[current.ipv4] = current by_macaddr[current.macaddr] = current else: # log that this lease entry is useless for us if without a mac address or binding state isn't active pass del current state = NOWHERE else: # XXX count number of unknown lease lines pass return by_ipv4, by_macaddr