You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
4.9 KiB

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