1# Copyright (c) 2014 Stefan C. Mueller 2 3# Permission is hereby granted, free of charge, to any person obtaining a copy 4# of this software and associated documentation files (the "Software"), to 5# deal in the Software without restriction, including without limitation the 6# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7# sell copies of the Software, and to permit persons to whom the Software is 8# furnished to do so, subject to the following conditions: 9# 10# The above copyright notice and this permission notice shall be included in 11# all copies or substantial portions of the Software. 12# 13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19# IN THE SOFTWARE. 20 21 22import ctypes 23from ctypes import wintypes 24 25import ifaddr._shared as shared 26 27NO_ERROR=0 28ERROR_BUFFER_OVERFLOW = 111 29MAX_ADAPTER_NAME_LENGTH = 256 30MAX_ADAPTER_DESCRIPTION_LENGTH = 128 31MAX_ADAPTER_ADDRESS_LENGTH = 8 32AF_UNSPEC = 0 33 34 35 36class SOCKET_ADDRESS(ctypes.Structure): 37 _fields_ = [('lpSockaddr', ctypes.POINTER(shared.sockaddr)), 38 ('iSockaddrLength', wintypes.INT)] 39 40class IP_ADAPTER_UNICAST_ADDRESS(ctypes.Structure): 41 pass 42IP_ADAPTER_UNICAST_ADDRESS._fields_ = \ 43 [('Length', wintypes.ULONG), 44 ('Flags', wintypes.DWORD), 45 ('Next', ctypes.POINTER(IP_ADAPTER_UNICAST_ADDRESS)), 46 ('Address', SOCKET_ADDRESS), 47 ('PrefixOrigin', ctypes.c_uint), 48 ('SuffixOrigin', ctypes.c_uint), 49 ('DadState', ctypes.c_uint), 50 ('ValidLifetime', wintypes.ULONG), 51 ('PreferredLifetime', wintypes.ULONG), 52 ('LeaseLifetime', wintypes.ULONG), 53 ('OnLinkPrefixLength', ctypes.c_uint8), 54 ] 55 56class IP_ADAPTER_ADDRESSES(ctypes.Structure): 57 pass 58IP_ADAPTER_ADDRESSES._fields_ = [('Length', wintypes.ULONG), 59 ('IfIndex', wintypes.DWORD), 60 ('Next', ctypes.POINTER(IP_ADAPTER_ADDRESSES)), 61 ('AdapterName', ctypes.c_char_p), 62 ('FirstUnicastAddress', ctypes.POINTER(IP_ADAPTER_UNICAST_ADDRESS)), 63 ('FirstAnycastAddress', ctypes.POINTER(None)), 64 ('FirstMulticastAddress', ctypes.POINTER(None)), 65 ('FirstDnsServerAddress', ctypes.POINTER(None)), 66 ('DnsSuffix', ctypes.c_wchar_p), 67 ('Description', ctypes.c_wchar_p), 68 ('FriendlyName', ctypes.c_wchar_p) 69 ] 70 71 72iphlpapi = ctypes.windll.LoadLibrary("Iphlpapi") 73 74 75def enumerate_interfaces_of_adapter(nice_name, address): 76 77 # Iterate through linked list and fill list 78 addresses = [] 79 while True: 80 addresses.append(address) 81 if not address.Next: 82 break 83 address = address.Next[0] 84 85 for address in addresses: 86 ip = shared.sockaddr_to_ip(address.Address.lpSockaddr) 87 network_prefix = address.OnLinkPrefixLength 88 yield shared.IP(ip, network_prefix, nice_name) 89 90 91def get_adapters(): 92 93 # Call GetAdaptersAddresses() with error and buffer size handling 94 95 addressbuffersize = wintypes.ULONG(15*1024) 96 retval = ERROR_BUFFER_OVERFLOW 97 while retval == ERROR_BUFFER_OVERFLOW: 98 addressbuffer = ctypes.create_string_buffer(addressbuffersize.value) 99 retval = iphlpapi.GetAdaptersAddresses(wintypes.ULONG(AF_UNSPEC), 100 wintypes.ULONG(0), 101 None, 102 ctypes.byref(addressbuffer), 103 ctypes.byref(addressbuffersize)) 104 if retval != NO_ERROR: 105 raise ctypes.WinError() 106 107 # Iterate through adapters fill array 108 address_infos = [] 109 address_info = IP_ADAPTER_ADDRESSES.from_buffer(addressbuffer) 110 while True: 111 address_infos.append(address_info) 112 if not address_info.Next: 113 break 114 address_info = address_info.Next[0] 115 116 117 # Iterate through unicast addresses 118 result = [] 119 for adapter_info in address_infos: 120 121 name = adapter_info.AdapterName 122 nice_name = adapter_info.Description 123 index = adapter_info.IfIndex 124 125 if adapter_info.FirstUnicastAddress: 126 ips = enumerate_interfaces_of_adapter(adapter_info.FriendlyName, adapter_info.FirstUnicastAddress[0]) 127 ips = list(ips) 128 result.append(shared.Adapter(name, nice_name, ips, 129 index=index)) 130 131 return result 132