def scan(self, ifindex, ssids=None, flush_cache=False): ''' Trigger scan and get results. Triggering scan usually requires root, and can take a couple of seconds. ''' # Prepare a second netlink socket to get the scan results. # The issue is that the kernel can send the results notification # before we get answer for the NL80211_CMD_TRIGGER_SCAN nsock = NL80211() nsock.bind() nsock.add_membership('scan') # send scan request msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_TRIGGER_SCAN'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex]] # If a list of SSIDs is provided, active scanning should be performed if ssids is not None: if isinstance(ssids, list): msg['attrs'].append(['NL80211_ATTR_SCAN_SSIDS', ssids]) scan_flags = 0 if flush_cache: # Flush the cache before scanning scan_flags |= SCAN_FLAGS_NAMES['NL80211_SCAN_FLAG_FLUSH'] msg['attrs'].append(['NL80211_ATTR_SCAN_FLAGS', scan_flags]) self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK) # monitor the results notification on the secondary socket scanResultNotFound = True while scanResultNotFound: listMsg = nsock.get() for msg in listMsg: if msg["event"] == "NL80211_CMD_NEW_SCAN_RESULTS": scanResultNotFound = False break # close the secondary socket nsock.close() # request the results msg2 = nl80211cmd() msg2['cmd'] = NL80211_NAMES['NL80211_CMD_GET_SCAN'] msg2['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex]] return self.nlm_request(msg2, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_DUMP)
def get_associated_bss(self, ifindex): ''' Returns the same info like scan() does, but only about the currently associated BSS. Unlike scan(), it returns immediately and doesn't require root. ''' # When getting scan results without triggering scan first, # you'll always get the information about currently associated BSS # # However, it may return other BSS, if last scan wasn't very # long time go msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_GET_SCAN'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex]] res = self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_DUMP) for x in res: attr_bss = x.get_attr('NL80211_ATTR_BSS') if attr_bss is not None: status = attr_bss.get_attr('NL80211_BSS_STATUS') if status in ( BSS_STATUS_NAMES['associated'], BSS_STATUS_NAMES['ibss_joined'], ): return x return None
def list_wiphy(self): ''' Get list of all phy devices ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_GET_WIPHY'] return self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_DUMP)
def get_interfaces_dump(self): ''' Get interfaces dump ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_GET_INTERFACE'] return self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_DUMP)
def survey(self, ifindex): ''' Return the survey info. ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_GET_SURVEY'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex]] return self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_DUMP)
def disconnect(self, ifindex): ''' Disconnect the device ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_DISCONNECT'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex]] self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def get_interface_by_ifindex(self, ifindex): ''' Get interface by ifindex ( use x.get_attr('NL80211_ATTR_IFINDEX') ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_GET_INTERFACE'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex]] return self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST)
def get_stations(self, ifindex): ''' Get stations by ifindex ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_GET_STATION'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex]] return self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_DUMP)
def get_interface_by_phy(self, attr): ''' Get interface by phy ( use x.get_attr('NL80211_ATTR_WIPHY') ) ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_GET_INTERFACE'] msg['attrs'] = [['NL80211_ATTR_WIPHY', attr]] return self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_DUMP)
def leave_ibss(self, ifindex): ''' Leave the IBSS -- the IBSS is determined by the network interface ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_LEAVE_IBSS'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex]] self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def set_regulatory_domain(self, alpha2): ''' Set regulatory domain. ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_REQ_SET_REG'] msg['attrs'] = [['NL80211_ATTR_REG_ALPHA2', alpha2]] self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def set_wiphy_netns_by_pid(self, wiphy, pid): ''' Set wiphy network namespace to process network namespace. ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_SET_WIPHY_NETNS'] msg['attrs'] = [['NL80211_ATTR_WIPHY', wiphy], ['NL80211_ATTR_PID', pid]] self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def del_interface(self, dev): ''' Delete a virtual interface - dev — device index ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_DEL_INTERFACE'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', dev]] self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def set_wiphy_netns_by_fd(self, wiphy, netns_fd): ''' Set wiphy network namespace to namespace referenced by fd. ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_SET_WIPHY_NETNS'] msg['attrs'] = [['NL80211_ATTR_WIPHY', wiphy], ['NL80211_ATTR_NETNS_FD', netns_fd]] self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def disassociate(self, ifindex, bssid, reason_code=0x03): ''' Send a Disassociation management frame. ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_DISASSOCIATE'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex], ['NL80211_ATTR_MAC', bssid], ['NL80211_ATTR_REASON_CODE', reason_code]] self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def connect(self, ifindex, ssid, bssid=None): ''' Connect to the ap with ssid and bssid ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_CONNECT'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex], ['NL80211_ATTR_SSID', ssid]] if bssid is not None: msg['attrs'].append(['NL80211_ATTR_MAC', bssid]) self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def get_regulatory_domain(self, attr=None): ''' Get regulatory domain information. If attr specified, get regulatory domain information for this device ( use x.get_attr('NL80211_ATTR_WIPHY') ). ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_GET_REG'] flags = NLM_F_REQUEST if attr is None: flags |= NLM_F_DUMP else: msg['attrs'] = [['NL80211_ATTR_WIPHY', attr]] return self.nlm_request(msg, msg_type=self.prid, msg_flags=flags)
def deauthenticate(self, ifindex, bssid, reason_code=0x01): ''' Send a Deauthentication management frame. ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_DEAUTHENTICATE'] msg['attrs'] = [ ['NL80211_ATTR_IFINDEX', ifindex], ['NL80211_ATTR_MAC', bssid], ['NL80211_ATTR_REASON_CODE', reason_code], ] self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def authenticate(self, ifindex, bssid, ssid, freq, auth_type=0): ''' Send an Authentication management frame. ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_AUTHENTICATE'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex], ['NL80211_ATTR_MAC', bssid], ['NL80211_ATTR_SSID', ssid], ['NL80211_ATTR_WIPHY_FREQ', freq], ['NL80211_ATTR_AUTH_TYPE', auth_type]] self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def add_interface(self, ifname, iftype, dev=None, phy=0): ''' Create a virtual interface - ifname — name of the interface to create - iftype — interface type to create - dev — device index - phy — phy index One should specify `dev` (device index) or `phy` (phy index). If no one specified, phy == 0. `iftype` can be integer or string: 1. adhoc 2. station 3. ap 4. ap_vlan 5. wds 6. monitor 7. mesh_point 8. p2p_client 9. p2p_go 10. p2p_device 11. ocb ''' # lookup the interface type iftype = IFTYPE_NAMES.get(iftype, iftype) assert isinstance(iftype, int) msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_NEW_INTERFACE'] msg['attrs'] = [ ['NL80211_ATTR_IFNAME', ifname], ['NL80211_ATTR_IFTYPE', iftype], ] if dev is not None: msg['attrs'].append(['NL80211_ATTR_IFINDEX', dev]) elif phy is not None: msg['attrs'].append(['NL80211_ATTR_WIPHY', phy]) else: raise TypeError('no device specified') self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def associate(self, ifindex, bssid, ssid, freq, info_elements=None): ''' Send an Association request frame. ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_ASSOCIATE'] msg['attrs'] = [['NL80211_ATTR_IFINDEX', ifindex], ['NL80211_ATTR_MAC', bssid], ['NL80211_ATTR_SSID', ssid], ['NL80211_ATTR_WIPHY_FREQ', freq]] if info_elements is not None: msg['attrs'].append(['NL80211_ATTR_IE', info_elements]) self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def set_tx_power(self, dev, mode, mbm=None): ''' Set TX power of interface. - dev — device index - mode — TX power setting (0 - auto, 1 - limit, 2 - fixed) - mbm — TX power in mBm (dBm * 100) ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_SET_WIPHY'] msg['attrs'] = [ ['NL80211_ATTR_IFINDEX', dev], ['NL80211_ATTR_WIPHY_TX_POWER_SETTING', mode], ] if mbm is not None: msg['attrs'].append(['NL80211_ATTR_WIPHY_TX_POWER_LEVEL', mbm]) self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)
def join_ibss( self, ifindex, ssid, freq, bssid=None, channel_fixed=False, width=None, center=None, center2=None, ): ''' Connect to network by ssid - ifindex - IFINDEX of the interface to perform the connection - ssid - Service set identification - freq - Frequency in MHz - bssid - The MAC address of target interface - channel_fixed: Boolean flag - width - Channel width - center - Central frequency of the 40/80/160 MHz channel - center2 - Center frequency of second segment if 80P80 If the flag of channel_fixed is True, one should specify both the width and center of the channel `width` can be integer of string: 0. 20_noht 1. 20 2. 40 3. 80 4. 80p80 5. 160 6. 5 7. 10 ''' msg = nl80211cmd() msg['cmd'] = NL80211_NAMES['NL80211_CMD_JOIN_IBSS'] msg['attrs'] = [ ['NL80211_ATTR_IFINDEX', ifindex], ['NL80211_ATTR_SSID', ssid], ['NL80211_ATTR_WIPHY_FREQ', freq], ] if channel_fixed: msg['attrs'].append(['NL80211_ATTR_FREQ_FIXED', None]) width = CHAN_WIDTH.get(width, width) assert isinstance(width, int) if width in [2, 3, 5] and center: msg['attrs'].append(['NL80211_ATTR_CHANNEL_WIDTH', width]) msg['attrs'].append(['NL80211_ATTR_CENTER_FREQ1', center]) elif width == 4 and center and center2: msg['attrs'].append(['NL80211_ATTR_CHANNEL_WIDTH', width]) msg['attrs'].append(['NL80211_ATTR_CENTER_FREQ1', center]) msg['attrs'].append(['NL80211_ATTR_CENTER_FREQ2', center2]) elif width in [0, 1, 6, 7]: msg['attrs'].append(['NL80211_ATTR_CHANNEL_WIDTH', width]) else: raise TypeError('No channel specified') if bssid is not None: msg['attrs'].append(['NL80211_ATTR_MAC', bssid]) self.nlm_request(msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK)