123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
- """
- Windows implementation of local network interface enumeration.
- """
- from socket import socket, AF_INET6, SOCK_STREAM
- from ctypes import (
- WinDLL, byref, create_string_buffer, create_unicode_buffer,
- c_int, c_void_p,
- POINTER, Structure, cast, wstring_at)
- WS2_32 = WinDLL('ws2_32')
- SOCKET = c_int
- DWORD = c_int
- LPVOID = c_void_p
- LPSOCKADDR = c_void_p
- LPWSAPROTOCOL_INFO = c_void_p
- LPTSTR = c_void_p
- LPDWORD = c_void_p
- LPWSAOVERLAPPED = c_void_p
- LPWSAOVERLAPPED_COMPLETION_ROUTINE = c_void_p
- # http://msdn.microsoft.com/en-us/library/ms741621(v=VS.85).aspx
- # int WSAIoctl(
- # __in SOCKET s,
- # __in DWORD dwIoControlCode,
- # __in LPVOID lpvInBuffer,
- # __in DWORD cbInBuffer,
- # __out LPVOID lpvOutBuffer,
- # __in DWORD cbOutBuffer,
- # __out LPDWORD lpcbBytesReturned,
- # __in LPWSAOVERLAPPED lpOverlapped,
- # __in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
- # );
- WSAIoctl = WS2_32.WSAIoctl
- WSAIoctl.argtypes = [
- SOCKET, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD,
- LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE]
- WSAIoctl.restype = c_int
- # http://msdn.microsoft.com/en-us/library/ms741516(VS.85).aspx
- # INT WSAAPI WSAAddressToString(
- # __in LPSOCKADDR lpsaAddress,
- # __in DWORD dwAddressLength,
- # __in_opt LPWSAPROTOCOL_INFO lpProtocolInfo,
- # __inout LPTSTR lpszAddressString,
- # __inout LPDWORD lpdwAddressStringLength
- # );
- WSAAddressToString = WS2_32.WSAAddressToStringW
- WSAAddressToString.argtypes = [
- LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFO, LPTSTR, LPDWORD]
- WSAAddressToString.restype = c_int
- SIO_ADDRESS_LIST_QUERY = 0x48000016
- WSAEFAULT = 10014
- class SOCKET_ADDRESS(Structure):
- _fields_ = [('lpSockaddr', c_void_p),
- ('iSockaddrLength', c_int)]
- def make_SAL(ln):
- class SOCKET_ADDRESS_LIST(Structure):
- _fields_ = [('iAddressCount', c_int),
- ('Address', SOCKET_ADDRESS * ln)]
- return SOCKET_ADDRESS_LIST
- def win32GetLinkLocalIPv6Addresses():
- """
- Return a list of strings in colon-hex format representing all the link local
- IPv6 addresses available on the system, as reported by
- I{WSAIoctl}/C{SIO_ADDRESS_LIST_QUERY}.
- """
- s = socket(AF_INET6, SOCK_STREAM)
- size = 4096
- retBytes = c_int()
- for i in range(2):
- buf = create_string_buffer(size)
- ret = WSAIoctl(
- s.fileno(),
- SIO_ADDRESS_LIST_QUERY, 0, 0, buf, size, byref(retBytes), 0, 0)
- # WSAIoctl might fail with WSAEFAULT, which means there was not enough
- # space in the buffer we gave it. There's no way to check the errno
- # until Python 2.6, so we don't even try. :/ Maybe if retBytes is still
- # 0 another error happened, though.
- if ret and retBytes.value:
- size = retBytes.value
- else:
- break
- # If it failed, then we'll just have to give up. Still no way to see why.
- if ret:
- raise RuntimeError("WSAIoctl failure")
- addrList = cast(buf, POINTER(make_SAL(0)))
- addrCount = addrList[0].iAddressCount
- addrList = cast(buf, POINTER(make_SAL(addrCount)))
- addressStringBufLength = 1024
- addressStringBuf = create_unicode_buffer(addressStringBufLength)
- retList = []
- for i in range(addrList[0].iAddressCount):
- retBytes.value = addressStringBufLength
- address = addrList[0].Address[i]
- ret = WSAAddressToString(
- address.lpSockaddr, address.iSockaddrLength, 0, addressStringBuf,
- byref(retBytes))
- if ret:
- raise RuntimeError("WSAAddressToString failure")
- retList.append(wstring_at(addressStringBuf))
- return [addr for addr in retList if '%' in addr]
|