""" Some routines for retrieving the addresses from the local network config. """ from __future__ import print_function import itertools import ctypes from jaraco.windows.api import errors, inet def GetAdaptersAddresses(): size = ctypes.c_ulong() res = inet.GetAdaptersAddresses(0, 0, None, None, size) if res != errors.ERROR_BUFFER_OVERFLOW: raise RuntimeError("Error getting structure length (%d)" % res) print(size.value) pointer_type = ctypes.POINTER(inet.IP_ADAPTER_ADDRESSES) buffer = ctypes.create_string_buffer(size.value) struct_p = ctypes.cast(buffer, pointer_type) res = inet.GetAdaptersAddresses(0, 0, None, struct_p, size) if res != errors.NO_ERROR: raise RuntimeError("Error retrieving table (%d)" % res) while struct_p: yield struct_p.contents struct_p = struct_p.contents.next class AllocatedTable(object): """ Both the interface table and the ip address table use the same technique to store arrays of structures of variable length. This base class captures the functionality to retrieve and access those table entries. The subclass needs to define three class attributes: method: a callable that takes three arguments - a pointer to the structure, the length of the data contained by the structure, and a boolean of whether the result should be sorted. structure: a C structure defininition that describes the table format. row_structure: a C structure definition that describes the row format. """ def __get_table_size(self): """ Retrieve the size of the buffer needed by calling the method with a null pointer and length of zero. This should trigger an insufficient buffer error and return the size needed for the buffer. """ length = ctypes.wintypes.DWORD() res = self.method(None, length, False) if res != errors.ERROR_INSUFFICIENT_BUFFER: raise RuntimeError("Error getting table length (%d)" % res) return length.value def get_table(self): """ Get the table """ buffer_length = self.__get_table_size() returned_buffer_length = ctypes.wintypes.DWORD(buffer_length) buffer = ctypes.create_string_buffer(buffer_length) pointer_type = ctypes.POINTER(self.structure) table_p = ctypes.cast(buffer, pointer_type) res = self.method(table_p, returned_buffer_length, False) if res != errors.NO_ERROR: raise RuntimeError("Error retrieving table (%d)" % res) return table_p.contents @property def entries(self): """ Using the table structure, return the array of entries based on the table size. """ table = self.get_table() entries_array = self.row_structure * table.num_entries pointer_type = ctypes.POINTER(entries_array) return ctypes.cast(table.entries, pointer_type).contents class InterfaceTable(AllocatedTable): method = inet.GetIfTable structure = inet.MIB_IFTABLE row_structure = inet.MIB_IFROW class AddressTable(AllocatedTable): method = inet.GetIpAddrTable structure = inet.MIB_IPADDRTABLE row_structure = inet.MIB_IPADDRROW class AddressManager(object): @staticmethod def hardware_address_to_string(addr): hex_bytes = (byte.encode('hex') for byte in addr) return ':'.join(hex_bytes) def get_host_mac_address_strings(self): return ( self.hardware_address_to_string(addr) for addr in self.get_host_mac_addresses()) def get_host_ip_address_strings(self): return itertools.imap(str, self.get_host_ip_addresses()) def get_host_mac_addresses(self): return ( entry.physical_address for entry in InterfaceTable().entries ) def get_host_ip_addresses(self): return ( entry.address for entry in AddressTable().entries )