_win32ifaces.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Windows implementation of local network interface enumeration.
  5. """
  6. from socket import socket, AF_INET6, SOCK_STREAM
  7. from ctypes import (
  8. WinDLL, byref, create_string_buffer, create_unicode_buffer,
  9. c_int, c_void_p,
  10. POINTER, Structure, cast, wstring_at)
  11. WS2_32 = WinDLL('ws2_32')
  12. SOCKET = c_int
  13. DWORD = c_int
  14. LPVOID = c_void_p
  15. LPSOCKADDR = c_void_p
  16. LPWSAPROTOCOL_INFO = c_void_p
  17. LPTSTR = c_void_p
  18. LPDWORD = c_void_p
  19. LPWSAOVERLAPPED = c_void_p
  20. LPWSAOVERLAPPED_COMPLETION_ROUTINE = c_void_p
  21. # http://msdn.microsoft.com/en-us/library/ms741621(v=VS.85).aspx
  22. # int WSAIoctl(
  23. # __in SOCKET s,
  24. # __in DWORD dwIoControlCode,
  25. # __in LPVOID lpvInBuffer,
  26. # __in DWORD cbInBuffer,
  27. # __out LPVOID lpvOutBuffer,
  28. # __in DWORD cbOutBuffer,
  29. # __out LPDWORD lpcbBytesReturned,
  30. # __in LPWSAOVERLAPPED lpOverlapped,
  31. # __in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
  32. # );
  33. WSAIoctl = WS2_32.WSAIoctl
  34. WSAIoctl.argtypes = [
  35. SOCKET, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD,
  36. LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE]
  37. WSAIoctl.restype = c_int
  38. # http://msdn.microsoft.com/en-us/library/ms741516(VS.85).aspx
  39. # INT WSAAPI WSAAddressToString(
  40. # __in LPSOCKADDR lpsaAddress,
  41. # __in DWORD dwAddressLength,
  42. # __in_opt LPWSAPROTOCOL_INFO lpProtocolInfo,
  43. # __inout LPTSTR lpszAddressString,
  44. # __inout LPDWORD lpdwAddressStringLength
  45. # );
  46. WSAAddressToString = WS2_32.WSAAddressToStringW
  47. WSAAddressToString.argtypes = [
  48. LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFO, LPTSTR, LPDWORD]
  49. WSAAddressToString.restype = c_int
  50. SIO_ADDRESS_LIST_QUERY = 0x48000016
  51. WSAEFAULT = 10014
  52. class SOCKET_ADDRESS(Structure):
  53. _fields_ = [('lpSockaddr', c_void_p),
  54. ('iSockaddrLength', c_int)]
  55. def make_SAL(ln):
  56. class SOCKET_ADDRESS_LIST(Structure):
  57. _fields_ = [('iAddressCount', c_int),
  58. ('Address', SOCKET_ADDRESS * ln)]
  59. return SOCKET_ADDRESS_LIST
  60. def win32GetLinkLocalIPv6Addresses():
  61. """
  62. Return a list of strings in colon-hex format representing all the link local
  63. IPv6 addresses available on the system, as reported by
  64. I{WSAIoctl}/C{SIO_ADDRESS_LIST_QUERY}.
  65. """
  66. s = socket(AF_INET6, SOCK_STREAM)
  67. size = 4096
  68. retBytes = c_int()
  69. for i in range(2):
  70. buf = create_string_buffer(size)
  71. ret = WSAIoctl(
  72. s.fileno(),
  73. SIO_ADDRESS_LIST_QUERY, 0, 0, buf, size, byref(retBytes), 0, 0)
  74. # WSAIoctl might fail with WSAEFAULT, which means there was not enough
  75. # space in the buffer we gave it. There's no way to check the errno
  76. # until Python 2.6, so we don't even try. :/ Maybe if retBytes is still
  77. # 0 another error happened, though.
  78. if ret and retBytes.value:
  79. size = retBytes.value
  80. else:
  81. break
  82. # If it failed, then we'll just have to give up. Still no way to see why.
  83. if ret:
  84. raise RuntimeError("WSAIoctl failure")
  85. addrList = cast(buf, POINTER(make_SAL(0)))
  86. addrCount = addrList[0].iAddressCount
  87. addrList = cast(buf, POINTER(make_SAL(addrCount)))
  88. addressStringBufLength = 1024
  89. addressStringBuf = create_unicode_buffer(addressStringBufLength)
  90. retList = []
  91. for i in range(addrList[0].iAddressCount):
  92. retBytes.value = addressStringBufLength
  93. address = addrList[0].Address[i]
  94. ret = WSAAddressToString(
  95. address.lpSockaddr, address.iSockaddrLength, 0, addressStringBuf,
  96. byref(retBytes))
  97. if ret:
  98. raise RuntimeError("WSAAddressToString failure")
  99. retList.append(wstring_at(addressStringBuf))
  100. return [addr for addr in retList if '%' in addr]