mirror of
https://github.com/markqvist/Sideband.git
synced 2024-12-12 17:34:32 -05:00
573 lines
15 KiB
Python
573 lines
15 KiB
Python
'''
|
|
Reference
|
|
Methods, Structures and Documentation adapted from.
|
|
https://msdn.microsoft.com/en-us/library/windows/desktop \
|
|
/ms705945%28v=vs.85%29.aspx
|
|
'''
|
|
|
|
from ctypes import (
|
|
POINTER,
|
|
FormatError,
|
|
Structure,
|
|
addressof,
|
|
byref,
|
|
c_bool,
|
|
c_char,
|
|
c_ubyte,
|
|
c_uint,
|
|
c_ulong,
|
|
c_ushort,
|
|
c_void_p,
|
|
c_wchar,
|
|
pointer,
|
|
windll,
|
|
)
|
|
from ctypes.wintypes import DWORD, HANDLE, LPCWSTR, ULONG
|
|
from sys import exit as sys_exit
|
|
|
|
|
|
def customresize(array, new_size):
|
|
return (
|
|
array._type_ * new_size
|
|
).from_address(
|
|
addressof(array)
|
|
)
|
|
|
|
|
|
wlanapi = windll.LoadLibrary('wlanapi.dll')
|
|
|
|
|
|
class GUID(Structure):
|
|
_fields_ = [
|
|
('Data1', c_ulong),
|
|
('Data2', c_ushort),
|
|
('Data3', c_ushort),
|
|
('Data4', c_ubyte * 8),
|
|
]
|
|
|
|
|
|
# The WLAN_INTERFACE_STATE enumerated type indicates the state of an interface.
|
|
WLAN_INTERFACE_STATE = c_uint
|
|
(wlan_interface_state_not_ready,
|
|
wlan_interface_state_connected,
|
|
wlan_interface_state_ad_hoc_network_formed,
|
|
wlan_interface_state_disconnecting,
|
|
wlan_interface_state_disconnected,
|
|
wlan_interface_state_associating,
|
|
wlan_interface_state_discovering,
|
|
wlan_interface_state_authenticating) = map(WLAN_INTERFACE_STATE,
|
|
range(0, 8))
|
|
|
|
|
|
class WLAN_INTERFACE_INFO(Structure):
|
|
'''
|
|
The WLAN_INTERFACE_STATE enumerated type indicates the state of an
|
|
interface.
|
|
'''
|
|
_fields_ = [
|
|
("InterfaceGuid", GUID),
|
|
("strInterfaceDescription", c_wchar * 256),
|
|
("isState", WLAN_INTERFACE_STATE)
|
|
]
|
|
|
|
|
|
class WLAN_INTERFACE_INFO_LIST(Structure):
|
|
'''
|
|
The WLAN_INTERFACE_INFO_LIST structure contains an array of NIC interface
|
|
information.
|
|
'''
|
|
_fields_ = [
|
|
("NumberOfItems", DWORD),
|
|
("Index", DWORD),
|
|
("InterfaceInfo", WLAN_INTERFACE_INFO * 1)
|
|
]
|
|
|
|
|
|
DOT11_MAC_ADDRESS = c_ubyte * 6
|
|
WLAN_MAX_PHY_TYPE_NUMBER = 0x8
|
|
DOT11_SSID_MAX_LENGTH = 32
|
|
WLAN_REASON_CODE = DWORD
|
|
|
|
DOT11_BSS_TYPE = c_uint
|
|
(dot11_BSS_type_infrastructure,
|
|
dot11_BSS_type_independent,
|
|
dot11_BSS_type_any) = map(DOT11_BSS_TYPE, range(1, 4))
|
|
|
|
# The DOT11_PHY_TYPE enumeration defines an 802.11 PHY and media type.
|
|
DOT11_PHY_TYPE = c_uint
|
|
dot11_phy_type_unknown = 0
|
|
dot11_phy_type_any = 0
|
|
dot11_phy_type_fhss = 1
|
|
dot11_phy_type_dsss = 2
|
|
dot11_phy_type_irbaseband = 3
|
|
dot11_phy_type_ofdm = 4
|
|
dot11_phy_type_hrdsss = 5
|
|
dot11_phy_type_erp = 6
|
|
dot11_phy_type_ht = 7
|
|
dot11_phy_type_IHV_start = 0x80000000
|
|
dot11_phy_type_IHV_end = 0xffffffff
|
|
|
|
# The DOT11_AUTH_ALGORITHM enumerated type defines a wireless
|
|
# LAN authentication algorithm.
|
|
DOT11_AUTH_ALGORITHM = c_uint
|
|
DOT11_AUTH_ALGO_80211_OPEN = 1
|
|
DOT11_AUTH_ALGO_80211_SHARED_KEY = 2
|
|
DOT11_AUTH_ALGO_WPA = 3
|
|
DOT11_AUTH_ALGO_WPA_PSK = 4
|
|
DOT11_AUTH_ALGO_WPA_NONE = 5
|
|
DOT11_AUTH_ALGO_RSNA = 6
|
|
DOT11_AUTH_ALGO_RSNA_PSK = 7
|
|
DOT11_AUTH_ALGO_IHV_START = 0x80000000
|
|
DOT11_AUTH_ALGO_IHV_END = 0xffffffff
|
|
|
|
# The DOT11_CIPHER_ALGORITHM enumerated type defines a cipher
|
|
# algorithm for data encryption and decryption.
|
|
DOT11_CIPHER_ALGORITHM = c_uint
|
|
DOT11_CIPHER_ALGO_NONE = 0x00
|
|
DOT11_CIPHER_ALGO_WEP40 = 0x01
|
|
DOT11_CIPHER_ALGO_TKIP = 0x02
|
|
DOT11_CIPHER_ALGO_CCMP = 0x04
|
|
DOT11_CIPHER_ALGO_WEP104 = 0x05
|
|
DOT11_CIPHER_ALGO_WPA_USE_GROUP = 0x100
|
|
DOT11_CIPHER_ALGO_RSN_USE_GROUP = 0x100
|
|
DOT11_CIPHER_ALGO_WEP = 0x101
|
|
DOT11_CIPHER_ALGO_IHV_START = 0x80000000
|
|
DOT11_CIPHER_ALGO_IHV_END = 0xffffffff
|
|
|
|
|
|
class DOT11_SSID(Structure):
|
|
'''
|
|
A DOT11_SSID structure contains the SSID of an interface
|
|
'''
|
|
_fields_ = [
|
|
("SSIDLength", c_ulong),
|
|
("SSID", c_char * DOT11_SSID_MAX_LENGTH)
|
|
]
|
|
|
|
|
|
# Enumerated type to define the code of connection.
|
|
WLAN_CONNECTION_MODE = c_uint
|
|
(wlan_connection_mode_profile,
|
|
wlan_connection_mode_temporary_profile,
|
|
wlan_connection_mode_discovery_secure,
|
|
wlan_connection_mode_discovery_unsecure,
|
|
wlan_connection_mode_auto,
|
|
wlan_connection_mode_invalid) = map(WLAN_CONNECTION_MODE, range(0, 6))
|
|
|
|
|
|
class NDIS_OBJECT_HEADER(Structure):
|
|
'''
|
|
This Structure packages the object type, version, and size information
|
|
that is required in many NDIS (Netword Driver interface Specification)
|
|
Structures.
|
|
'''
|
|
_fields_ = [
|
|
("Type", c_char),
|
|
("Revision", c_char),
|
|
("Size", c_ushort)]
|
|
|
|
|
|
class DOT11_BSSID_LIST(Structure):
|
|
'''
|
|
The DOT11_BSSID_LIST structure contains a list of basic service set (BSS)
|
|
identifiers.
|
|
'''
|
|
_fields_ = [
|
|
("Header", NDIS_OBJECT_HEADER),
|
|
("uNumOfEntries", ULONG),
|
|
("uTotalNumOfEntries", ULONG),
|
|
("BSSIDs", DOT11_MAC_ADDRESS * 1)
|
|
]
|
|
|
|
|
|
class WLAN_CONNECTION_PARAMETERS(Structure):
|
|
'''
|
|
The WLAN_CONNECTION_PARAMETERS structure specifies the parameters used when
|
|
using the WlanConnect function.
|
|
'''
|
|
_fields_ = [
|
|
("wlanConnectionMode", WLAN_CONNECTION_MODE),
|
|
("strProfile", LPCWSTR),
|
|
("pDot11Ssid", POINTER(DOT11_SSID)),
|
|
("pDesiredBssidList", POINTER(DOT11_BSSID_LIST)),
|
|
("dot11BssType", DOT11_BSS_TYPE),
|
|
("dwFlags", DWORD)]
|
|
|
|
|
|
# The `WlanConnect` attempts to connect to a specific network.
|
|
WlanConnect = wlanapi.WlanConnect
|
|
WlanConnect.argtypes = (HANDLE,
|
|
POINTER(GUID),
|
|
POINTER(WLAN_CONNECTION_PARAMETERS),
|
|
c_void_p)
|
|
WlanConnect.restype = DWORD
|
|
|
|
# The `WlanDisconnect` method disconnects an interface from its
|
|
# current network.
|
|
WlanDisconnect = wlanapi.WlanDisconnect
|
|
WlanDisconnect.argtypes = (HANDLE,
|
|
POINTER(GUID),
|
|
c_void_p)
|
|
WlanDisconnect.restype = DWORD
|
|
|
|
# Opens a connection to the server.
|
|
WlanOpenHandle = wlanapi.WlanOpenHandle
|
|
WlanOpenHandle.argtypes = (DWORD, c_void_p, POINTER(DWORD), POINTER(HANDLE))
|
|
WlanOpenHandle.restype = DWORD
|
|
|
|
# The WlanCloseHandle method closes the connection to the server.
|
|
WlanCloseHandle = wlanapi.WlanCloseHandle
|
|
WlanCloseHandle.argtypes = (HANDLE, c_void_p)
|
|
WlanCloseHandle.restype = DWORD
|
|
|
|
|
|
class WLAN_AVAILABLE_NETWORK(Structure):
|
|
'''
|
|
The WLAN_INTERFACE_INFO structure contains information about a wireless
|
|
LAN interface.
|
|
'''
|
|
_fields_ = [
|
|
("ProfileName", c_wchar * 256),
|
|
("dot11Ssid", DOT11_SSID),
|
|
("dot11BssType", DOT11_BSS_TYPE),
|
|
("NumberOfBssids", c_ulong),
|
|
("NetworkConnectable", c_bool),
|
|
("wlanNotConnectableReason", WLAN_REASON_CODE),
|
|
("NumberOfPhyTypes", c_ulong),
|
|
("dot11PhyTypes", DOT11_PHY_TYPE * WLAN_MAX_PHY_TYPE_NUMBER),
|
|
("MorePhyTypes", c_bool),
|
|
("wlanSignalQuality", c_ulong),
|
|
("SecurityEnabled", c_bool),
|
|
("dot11DefaultAuthAlgorithm", DOT11_AUTH_ALGORITHM),
|
|
("dot11DefaultCipherAlgorithm", DOT11_CIPHER_ALGORITHM),
|
|
("Flags", DWORD),
|
|
("Reserved", DWORD)]
|
|
|
|
|
|
class WLAN_AVAILABLE_NETWORK_LIST(Structure):
|
|
'''
|
|
The WLAN_INTERFACE_INFO_LIST structure contains an array of NIC
|
|
interface information.
|
|
'''
|
|
_fields_ = [
|
|
("NumberOfItems", DWORD),
|
|
("Index", DWORD),
|
|
("Network", WLAN_AVAILABLE_NETWORK * 1)]
|
|
|
|
|
|
# The WlanEnumInterfaces function enumerates all of the wireless LAN interfaces
|
|
# currently enabled on the local computer.
|
|
WlanEnumInterfaces = wlanapi.WlanEnumInterfaces
|
|
WlanEnumInterfaces.argtypes = (HANDLE,
|
|
c_void_p,
|
|
POINTER(POINTER(WLAN_INTERFACE_INFO_LIST)))
|
|
WlanEnumInterfaces.restype = DWORD
|
|
|
|
# The WlanGetAvailableNetworkList function retrieves the list of available
|
|
# networks on a wireless LAN interface.
|
|
WlanGetAvailableNetworkList = wlanapi.WlanGetAvailableNetworkList
|
|
WlanGetAvailableNetworkList.argtypes = (HANDLE,
|
|
POINTER(GUID),
|
|
DWORD,
|
|
c_void_p,
|
|
POINTER(POINTER(
|
|
WLAN_AVAILABLE_NETWORK_LIST)))
|
|
WlanGetAvailableNetworkList.restype = DWORD
|
|
|
|
# The WlanFreeMemory function frees memory. Any memory returned from Native
|
|
# Wifi functions must be freed.
|
|
WlanFreeMemory = wlanapi.WlanFreeMemory
|
|
WlanFreeMemory.argtypes = [c_void_p]
|
|
|
|
wireless_interfaces = None
|
|
available = None
|
|
_dict = {}
|
|
|
|
# Private methods.
|
|
|
|
|
|
def _connect(network, parameters):
|
|
'''
|
|
Attempts to connect to a specific network.
|
|
'''
|
|
global _dict
|
|
wireless_interface = _dict[network]
|
|
|
|
wcp = WLAN_CONNECTION_PARAMETERS()
|
|
connection_mode = parameters['connection_mode']
|
|
wcp.wlanConnectionMode = WLAN_CONNECTION_MODE(connection_mode)
|
|
|
|
if connection_mode == 0 or connection_mode == 1:
|
|
wcp.strProfile = LPCWSTR(parameters["profile"])
|
|
else:
|
|
wcp.strProfile = None
|
|
|
|
dot11Ssid = DOT11_SSID()
|
|
try:
|
|
dot11Ssid.SSID = parameters["ssid"]
|
|
dot11Ssid.SSIDLength = len(parameters["ssid"])
|
|
except KeyError:
|
|
dot11Ssid.SSID = network
|
|
dot11Ssid.SSIDLength = len(network)
|
|
wcp.pDot11Ssid = pointer(dot11Ssid)
|
|
|
|
dot11bssid = DOT11_BSSID_LIST()
|
|
bssid = parameters["bssidList"]
|
|
dot11bssid.Header = bssid['Header']
|
|
dot11bssid.uNumOfEntries = bssid['uNumOfEntries']
|
|
dot11bssid.uTotalNumOfEntries = bssid['uTotalNumOfEntries']
|
|
dot11bssid.BSSIDs = bssid['BSSIDs']
|
|
|
|
wcp.pDesiredBssidList = pointer(dot11bssid)
|
|
|
|
bssType = parameters["bssType"]
|
|
wcp.dot11BssType = DOT11_BSS_TYPE(bssType)
|
|
|
|
wcp.dwFlags = DWORD(parameters["flags"])
|
|
|
|
NegotiatedVersion = DWORD()
|
|
ClientHandle = HANDLE()
|
|
|
|
wlan = WlanOpenHandle(1,
|
|
None,
|
|
byref(NegotiatedVersion),
|
|
byref(ClientHandle))
|
|
if wlan:
|
|
sys_exit(FormatError(wlan))
|
|
pInterfaceList = pointer(WLAN_INTERFACE_INFO_LIST())
|
|
wlan = WlanEnumInterfaces(ClientHandle, None, byref(pInterfaceList))
|
|
if wlan:
|
|
sys_exit(FormatError(wlan))
|
|
|
|
try:
|
|
wlan = WlanConnect(ClientHandle,
|
|
wireless_interface,
|
|
wcp,
|
|
None)
|
|
if wlan:
|
|
sys_exit(FormatError(wlan))
|
|
WlanCloseHandle(ClientHandle, None)
|
|
finally:
|
|
WlanFreeMemory(pInterfaceList)
|
|
|
|
|
|
def _disconnect():
|
|
'''
|
|
To disconnect an interface form the current network.
|
|
'''
|
|
NegotiatedVersion = DWORD()
|
|
ClientHandle = HANDLE()
|
|
|
|
wlan = WlanOpenHandle(
|
|
1,
|
|
None,
|
|
byref(NegotiatedVersion),
|
|
byref(ClientHandle)
|
|
)
|
|
if wlan:
|
|
sys_exit(FormatError(wlan))
|
|
|
|
pInterfaceList = pointer(WLAN_INTERFACE_INFO_LIST())
|
|
|
|
wlan = WlanEnumInterfaces(ClientHandle, None, byref(pInterfaceList))
|
|
if wlan:
|
|
sys_exit(FormatError(wlan))
|
|
|
|
result = None
|
|
try:
|
|
ifaces = customresize(
|
|
pInterfaceList.contents.InterfaceInfo,
|
|
pInterfaceList.contents.NumberOfItems
|
|
)
|
|
|
|
# find each available network for each interface
|
|
for iface in ifaces:
|
|
wlan = WlanDisconnect(
|
|
ClientHandle,
|
|
byref(iface.InterfaceGuid),
|
|
None
|
|
)
|
|
if wlan:
|
|
sys_exit(FormatError(wlan))
|
|
WlanCloseHandle(ClientHandle, None)
|
|
|
|
finally:
|
|
WlanFreeMemory(pInterfaceList)
|
|
result = get_available_wifi()
|
|
|
|
return result
|
|
|
|
|
|
def _start_scanning():
|
|
'''
|
|
Private method for scanning and returns the available devices.
|
|
'''
|
|
global available
|
|
global wireless_interfaces
|
|
NegotiatedVersion = DWORD()
|
|
ClientHandle = HANDLE()
|
|
|
|
wlan = WlanOpenHandle(
|
|
1,
|
|
None,
|
|
byref(NegotiatedVersion),
|
|
byref(ClientHandle)
|
|
)
|
|
|
|
if wlan:
|
|
sys_exit(FormatError(wlan))
|
|
|
|
# find all wireless network interfaces
|
|
pInterfaceList = pointer(WLAN_INTERFACE_INFO_LIST())
|
|
wlan = WlanEnumInterfaces(ClientHandle, None, byref(pInterfaceList))
|
|
if wlan:
|
|
sys_exit(FormatError(wlan))
|
|
|
|
result = None
|
|
try:
|
|
ifaces = customresize(
|
|
pInterfaceList.contents.InterfaceInfo,
|
|
pInterfaceList.contents.NumberOfItems
|
|
)
|
|
|
|
# find each available network for each interface
|
|
wireless_interfaces = ifaces
|
|
for iface in ifaces:
|
|
pAvailableNetworkList = pointer(WLAN_AVAILABLE_NETWORK_LIST())
|
|
wlan = WlanGetAvailableNetworkList(
|
|
ClientHandle,
|
|
byref(iface.InterfaceGuid),
|
|
0,
|
|
None,
|
|
byref(pAvailableNetworkList)
|
|
)
|
|
|
|
if wlan:
|
|
sys_exit(FormatError(wlan))
|
|
|
|
try:
|
|
avail_net_list = pAvailableNetworkList.contents
|
|
networks = customresize(
|
|
avail_net_list.Network,
|
|
avail_net_list.NumberOfItems
|
|
)
|
|
|
|
# Assigning the value of networks to the global variable
|
|
# `available`, so it could be used in other methods.
|
|
available = networks
|
|
_make_dict()
|
|
wlan = WlanDisconnect(
|
|
ClientHandle,
|
|
byref(iface.InterfaceGuid),
|
|
None
|
|
)
|
|
|
|
if wlan:
|
|
sys_exit(FormatError(wlan))
|
|
WlanCloseHandle(ClientHandle, None)
|
|
|
|
finally:
|
|
WlanFreeMemory(pAvailableNetworkList)
|
|
|
|
finally:
|
|
WlanFreeMemory(pInterfaceList)
|
|
result = get_available_wifi()
|
|
|
|
return result
|
|
|
|
|
|
def _get_network_info(name):
|
|
'''
|
|
returns the list of the network selected in a dict.
|
|
'''
|
|
global available
|
|
global _dict
|
|
|
|
net = _dict[name]
|
|
dot11BssType = net.dot11BssType
|
|
dot11DefaultAuthAlgorithm = net.dot11DefaultAuthAlgorithm
|
|
dot11DefaultCipherAlgorithm = net.dot11DefaultCipherAlgorithm
|
|
dot11PhyTypes = net.dot11PhyTypes[0]
|
|
dot11Ssid = net.dot11Ssid
|
|
wlanNotConnectableReason = net.wlanNotConnectableReason
|
|
wlanSignalQuality = net.wlanSignalQuality
|
|
return {"dot11BssType": dot11BssType,
|
|
"dot11DefaultAuthAlgorithm": dot11DefaultAuthAlgorithm,
|
|
"dot11DefaultCipherAlgorithm": dot11DefaultCipherAlgorithm,
|
|
"dot11PhyTypes": dot11PhyTypes,
|
|
"SSID": dot11Ssid.SSID,
|
|
"SSIDLength": dot11Ssid.SSIDLength,
|
|
"wlanNotConnectableReason": wlanNotConnectableReason,
|
|
"wlanSignalQuality": wlanSignalQuality}
|
|
|
|
|
|
def _make_dict():
|
|
'''
|
|
Prepares a dict so it could store network information.
|
|
'''
|
|
global available
|
|
global _dict
|
|
_dict = {}
|
|
for network in available:
|
|
_dict[network.dot11Ssid.SSID.decode('utf-8')] = network
|
|
|
|
|
|
def _get_available_wifi():
|
|
'''
|
|
returns the available wifi networks.
|
|
'''
|
|
global _dict
|
|
return _dict
|
|
|
|
|
|
def _is_enabled():
|
|
'''
|
|
Reason for returning true is explained in widi facade.
|
|
/plyer/facades/wifi.py
|
|
'''
|
|
return True
|
|
|
|
# public methods.
|
|
|
|
|
|
def is_enabled():
|
|
'''
|
|
calls private method `_is_enabled` and returns the result.
|
|
'''
|
|
return _is_enabled()
|
|
|
|
|
|
def connect(network, parameters):
|
|
'''
|
|
Connect to a network with following parameters.
|
|
'''
|
|
_connect(network=network, parameters=parameters)
|
|
|
|
|
|
def disconnect():
|
|
'''
|
|
Disconnect from a network.
|
|
'''
|
|
_disconnect()
|
|
|
|
|
|
def start_scanning():
|
|
'''
|
|
Start scanning for available wifi networks available.
|
|
'''
|
|
return _start_scanning()
|
|
|
|
|
|
def get_network_info(name):
|
|
'''
|
|
return the wifi network info.
|
|
'''
|
|
return _get_network_info(name=name)
|
|
|
|
|
|
def get_available_wifi():
|
|
'''
|
|
return the available wifi networks available
|
|
'''
|
|
return _get_available_wifi()
|