def ncsi_set_interface(ifindex, package, channel): sk = nl_socket_alloc() ret = genl_connect(sk) if ret < 0: return ret driver_id = genl_ctrl_resolve(sk, b'NCSI') if driver_id < 0: return driver_id msg = nlmsg_alloc() if package or package and channel: genlmsg_put(msg, 0, 0, driver_id, 0, 0, NCSI_CMD_SET_INTERFACE, 0) ret = nla_put_u32(msg, NCSI_ATTR_PACKAGE_ID, int(package)) if channel: ret = nla_put_u32(msg, NCSI_ATTR_CHANNEL_ID, int(channel)) else: genlmsg_put(msg, 0, 0, driver_id, 0, 0, NCSI_CMD_CLEAR_INTERFACE, 0) ret = nla_put_u32(msg, NCSI_ATTR_IFINDEX, ifindex) nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, dump_callback, None) ret = nl_send_auto(sk, msg) if ret < 0: print("Failed to send message: {}".format(ret)) return ret ret = nl_recvmsgs_default(sk) # blocks if ret < 0: reason = errmsg[abs(ret)] print("recvmsg returned {}, {}".format(ret, reason))
def scan_all_access_points(self): # Scan for access points within reach # First get the wireless interface index. pack = struct.pack('16sI', self.interface_name.encode('ascii'), 0) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: info = struct.unpack('16sI', fcntl.ioctl(sock.fileno(), 0x8933, pack)) except OSError: return logger.warning('Wireless interface {0}\ does not exist.'.format(self.interface_name)) finally: sock.close() if_index = int(info[1]) # Next open a socket to the kernel and bind to it. Same one used for # sending and receiving. self._nl_sock = nl_socket_alloc() # Creates an `nl_sock` instance. genl_connect(self._nl_sock) # Create file descriptor and bind socket. logger.debug('Finding the nl80211 driver ID...') driver_id = genl_ctrl_resolve(self._nl_sock, b'nl80211') logger.debug('Finding the nl80211 scanning group ID...') mcid = genl_ctrl_resolve_grp(self._nl_sock, b'nl80211', b'scan') # Scan for access points 1 or more (if requested) times. results = dict() for i in range(2, -1, -1): # Three tries on errors. ret = self._do_scan_trigger(if_index, driver_id, mcid) if ret < 0: logger.debug('do_scan_trigger() returned {0},' 'retrying in 5 seconds({1}).'.format(ret, i)) time.sleep(5) ret = self._do_scan_results(if_index, driver_id, results) if ret < 0: logger.debug('do_scan_results() returned {0},' 'retrying in 5 seconds ({1}).'.format(ret, i)) time.sleep(5) continue break if not results: logger.debug('No access points detected.') return [] logger.debug('Found {0} access points:'.format(len(results))) # Convert timedelta to integer to avoid # TypeError: Object of type timedelta is not JSON serializable for ap in results: for prop in results[ap]: if isinstance(results[ap][prop], datetime.timedelta): results[ap][prop] = int( results[ap][prop].microseconds) / 1000 return results
def scan_for_wifi_networks(interface): def db_to_percent(db): return 2.0 * (db + 100) pack = struct.pack('16sI', interface, 0) sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: info = struct.unpack('16sI', fcntl.ioctl(sk.fileno(), 0x8933, pack)) except OSError: raise RuntimeError( 'Wireless interface {0} does not exist.'.format(interface)) finally: sk.close() if_index = int(info[1]) # Next open a socket to the kernel and bind to it. Same one used for sending and receiving. sk = nl_socket_alloc() # Creates an `nl_sock` instance. if not genl_connect(sk) == 0: # Create file descriptor and bind socket. raise RuntimeError('Could not communicate with kernel via nl80211') driver_id = genl_ctrl_resolve(sk, b'nl80211') mcid = genl_ctrl_resolve_grp(sk, b'nl80211', b'scan') results = dict() for i in range(2, -1, -1): # Three tries on errors. ret = do_scan_trigger(sk, if_index, driver_id, mcid) if ret < 0: #timeout time.sleep(5) continue ret = do_scan_results(sk, if_index, driver_id, results) if ret < 0: time.sleep(5) continue break if not results: return {} ap_list = [] for _, f in results.items(): ssid = str(f['information_elements']['SSID']).encode("ascii", "ignore") if len(ssid) == 0: continue if u"\x00".encode("ascii", "ignore") in ssid: continue print(ssid, len(ssid)) # pp.pprint(f['information_elements']) security = 0 if 'RSN' in f['information_elements']: security = 1 signal_strength = db_to_percent(f['signal']) if signal_strength <= 25: continue network_tuple = [ssid, security, signal_strength] ap_list.append(network_tuple) return ap_list
def update_iface_details(self, cmd): # Send a command specified by CMD to the kernel and attach a callback to # process the returned values into our own datastructure self._nl_sock = nl_socket_alloc() # Creates an `nl_sock` instance. # Create file descriptor and bind socket. ret = genl_connect(self._nl_sock) if ret < 0: reason = errmsg[abs(ret)] logger.error('genl_connect() returned {0} ({1})'.format( ret, reason)) return {} # Now get the nl80211 driver ID. Handle errors here. # Find the nl80211 driver ID. driver_id = genl_ctrl_resolve(self._nl_sock, b'nl80211') if driver_id < 0: reason = errmsg[abs(driver_id)] logger.error('genl_ctrl_resolve() returned {0} ({1})'.format( driver_id, reason)) return {} # Setup the Generic Netlink message. msg = nlmsg_alloc() # Allocate a message. if self.if_idx == None: # Ask kernel to send info for all wireless interfaces. genlmsg_put(msg, 0, 0, driver_id, 0, NLM_F_DUMP, nl80211.NL80211_CMD_GET_INTERFACE, 0) else: genlmsg_put(msg, 0, 0, driver_id, 0, NLM_F_DUMP, cmd, 0) # This is the interface we care about. nla_put_u32(msg, nl80211.NL80211_ATTR_IFINDEX, self.if_idx) #nla_put_u32(msg, nl80211.NL80211_ATTR_MAC, 2199023255552) # Add the callback function to the self._nl_sock. nl_socket_modify_cb(self._nl_sock, NL_CB_VALID, NL_CB_CUSTOM, self._iface_callback, False) # Now send the message to the kernel, and get its response, # automatically calling the callback. ret = nl_send_auto(self._nl_sock, msg) if ret < 0: reason = errmsg[abs(ret)] logger.error('nl_send_auto() returned {0} ({1})'.format( ret, reason)) return {} logger.debug('Sent {0} bytes to the kernel.'.format(ret)) # Blocks until the kernel replies. Usually it's instant. ret = nl_recvmsgs_default(self._nl_sock) if ret < 0: reason = errmsg[abs(ret)] logger.error('nl_recvmsgs_default() returned {0} ({1})'.format( ret, reason)) return {}
def main(): """Main function called upon script execution.""" # First get the wireless interface index. if OPTIONS['<interface>']: pack = struct.pack('16sI', OPTIONS['<interface>'].encode('ascii'), 0) sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: info = struct.unpack('16sI', fcntl.ioctl(sk.fileno(), 0x8933, pack)) except OSError: return error('Wireless interface {0} does not exist.'.format(OPTIONS['<interface>'])) finally: sk.close() if_index = int(info[1]) else: if_index = -1 # Then open a socket to the kernel. Same one used for sending and receiving. sk = nl_socket_alloc() # Creates an `nl_sock` instance. ret = genl_connect(sk) # Create file descriptor and bind socket. if ret < 0: reason = errmsg[abs(ret)] return error('genl_connect() returned {0} ({1})'.format(ret, reason)) # Now get the nl80211 driver ID. Handle errors here. driver_id = genl_ctrl_resolve(sk, b'nl80211') # Find the nl80211 driver ID. if driver_id < 0: reason = errmsg[abs(driver_id)] return error('genl_ctrl_resolve() returned {0} ({1})'.format(driver_id, reason)) # Setup the Generic Netlink message. msg = nlmsg_alloc() # Allocate a message. if OPTIONS['<interface>']: genlmsg_put(msg, 0, 0, driver_id, 0, 0, nl80211.NL80211_CMD_GET_INTERFACE, 0) # Tell kernel: send iface info. nla_put_u32(msg, nl80211.NL80211_ATTR_IFINDEX, if_index) # This is the interface we care about. else: # Ask kernel to send info for all wireless interfaces. genlmsg_put(msg, 0, 0, driver_id, 0, NLM_F_DUMP, nl80211.NL80211_CMD_GET_INTERFACE, 0) # Add the callback function to the nl_sock. has_printed = list() nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, callback, has_printed) # Now send the message to the kernel, and get its response, automatically calling the callback. ret = nl_send_auto(sk, msg) if ret < 0: reason = errmsg[abs(ret)] return error('nl_send_auto() returned {0} ({1})'.format(ret, reason)) print('Sent {0} bytes to the kernel.'.format(ret)) ret = nl_recvmsgs_default(sk) # Blocks until the kernel replies. Usually it's instant. if ret < 0: reason = errmsg[abs(ret)] return error('nl_recvmsgs_default() returned {0} ({1})'.format(ret, reason))
def config_function(config): # Global variables storing conf and shared ressources global INTERFACE global CLIENTS global INTERFACEINDEX global VALUES global DRIVER_ID global SOCKET for node in config.children: key = node.key.lower() value = node.values[0] # Save Wi-Fi interface name if key == 'interface': INTERFACE = value collectd.info("Collecting stats for interface %s" % value) # Save a client MAC address elif key == 'client': CLIENTS.append(value) else: collectd.info("Unknown configuration key %s" % key) # No clients configured ? Store everything if len(CLIENTS) == 0: collectd.info("Collecting detailed stats for all clients") else: str_clients = "" for client in CLIENTS: str_clients = str_clients + " " + client collectd.info("Collecting stats for clients%s" % str_clients) # No Wi-FI interface configured if INTERFACE == "": collectd.error("No interface set in configuration") exit(1) else: # Get the interface index from the interface name pack = struct.pack('16sI', INTERFACE, 0) sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: info = struct.unpack('16sI', fcntl.ioctl(sk.fileno(), 0x8933, pack)) INTERFACEINDEX = int(info[1]) except IOError: collectd.error("Unknown network interface !") exit(1) # Create the netlink socket and resolve the driver id of extension nl80211 SOCKET = nl_socket_alloc() genl_connect(SOCKET) DRIVER_ID = genl_ctrl_resolve(SOCKET, b'nl80211')
def ncsi_get_info(ifindex, package): # Open socket to kernel sk = nl_socket_alloc() ret = genl_connect(sk) if ret < 0: print("Failed to open socket") return -1 # Find NCSI driver_id = genl_ctrl_resolve(sk, b'NCSI') if driver_id < 0: print("Could not resolve NCSI") return -1 # Setup up a Generic Netlink message msg = nlmsg_alloc() if package is None: ret = genlmsg_put(msg, 0, 0, driver_id, 0, NLM_F_DUMP, NCSI_CMD_PKG_INFO, 0) else: ret = genlmsg_put(msg, 0, 0, driver_id, 0, 0, NCSI_CMD_PKG_INFO, 0) nla_put_u32(msg, NCSI_ATTR_PACKAGE_ID, int(package)) if ret < 0: reason = errmsg[abs(ret)] print("genlmsg_put returned {}, {}".format(ret, reason)) return -1 nla_put_u32(msg, NCSI_ATTR_IFINDEX, ifindex) # Add a callback function to the socket nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, info_callback, None) ret = nl_send_auto(sk, msg) if ret < 0: print("Failed to send message: {}".format(ret)) return ret ret = nl_recvmsgs_default(sk) # blocks if ret < 0: reason = errmsg[abs(ret)] print("recvmsg returned {}, {}".format(ret, reason))
def main(): """Main function called upon script execution.""" # First get the wireless interface index. if OPTIONS['<interface>']: pack = struct.pack('16sI', OPTIONS['<interface>'].encode('ascii'), 0) sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: info = struct.unpack('16sI', fcntl.ioctl(sk.fileno(), 0x8933, pack)) except OSError: return error('Wireless interface {0} does not exist.'.format( OPTIONS['<interface>'])) finally: sk.close() if_index = int(info[1]) else: if_index = -1 # Then open a socket to the kernel. Same one used for sending and receiving. sk = nl_socket_alloc() # Creates an `nl_sock` instance. ret = genl_connect(sk) # Create file descriptor and bind socket. if ret < 0: reason = errmsg[abs(ret)] return error('genl_connect() returned {0} ({1})'.format(ret, reason)) # Now get the nl80211 driver ID. Handle errors here. driver_id = genl_ctrl_resolve(sk, b'nl80211') # Find the nl80211 driver ID. if driver_id < 0: reason = errmsg[abs(driver_id)] return error('genl_ctrl_resolve() returned {0} ({1})'.format( driver_id, reason)) # Setup the Generic Netlink message. msg = nlmsg_alloc() # Allocate a message. if OPTIONS['<interface>']: genlmsg_put(msg, 0, 0, driver_id, 0, 0, nl80211.NL80211_CMD_GET_INTERFACE, 0) # Tell kernel: send iface info. nla_put_u32(msg, nl80211.NL80211_ATTR_IFINDEX, if_index) # This is the interface we care about. else: # Ask kernel to send info for all wireless interfaces. genlmsg_put(msg, 0, 0, driver_id, 0, NLM_F_DUMP, nl80211.NL80211_CMD_GET_INTERFACE, 0) # Add the callback function to the nl_sock. has_printed = list() nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, callback, has_printed) # Now send the message to the kernel, and get its response, automatically calling the callback. ret = nl_send_auto(sk, msg) if ret < 0: reason = errmsg[abs(ret)] return error('nl_send_auto() returned {0} ({1})'.format(ret, reason)) print('Sent {0} bytes to the kernel.'.format(ret)) ret = nl_recvmsgs_default( sk) # Blocks until the kernel replies. Usually it's instant. if ret < 0: reason = errmsg[abs(ret)] return error('nl_recvmsgs_default() returned {0} ({1})'.format( ret, reason))
def test_genl_ctrl_resolve(log): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && NLDBG=4 NLCB=debug ./a.out #include <netlink/msg.h> int main() { struct nl_sock *sk = nl_socket_alloc(); printf("%d == genl_connect(sk)\n", genl_connect(sk)); int driver_id = genl_ctrl_resolve(sk, "nl80211"); printf("%d == driver_id\n", driver_id); nl_socket_free(sk); return 0; } // Expected output (trimmed): // nl_cache_mngt_register: Registered cache operations genl/family // 0 == genl_connect(sk) // nl_object_alloc: Allocated new object 0x6f90b8 // __nlmsg_alloc: msg 0x6f9110: Allocated new message, maxlen=4096 // nlmsg_put: msg 0x6f9110: Added netlink header type=16, flags=0, pid=0, seq=0 // nlmsg_reserve: msg 0x6f9110: Reserved 4 (4) bytes, pad=4, nlmsg_len=20 // genlmsg_put: msg 0x6f9110: Added generic netlink header cmd=3 version=1 // nla_reserve: msg 0x6f9110: attr <0x6f9164> 2: Reserved 12 (8) bytes at offset +4 nlmsg_len=32 // nla_put: msg 0x6f9110: attr <0x6f9164> 2: Wrote 8 bytes at offset +4 // -- Debug: Sent Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 32 // .type = 16 <genl/family::nlctrl> // .flags = 5 <REQUEST,ACK> // .seq = 1425769691 // .port = 2568 // [GENERIC NETLINK HEADER] 4 octets // .cmd = 3 // .version = 1 // .unused = 0 // [ATTR 02] 8 octets // 6e 6c 38 30 32 31 31 00 nl80211. // --------------------------- END NETLINK MESSAGE --------------------------- // nl_sendmsg: sent 32 bytes // recvmsgs: Attempting to read from 0x6f9080 // recvmsgs: recvmsgs(0x6f9080): Read 1836 bytes // recvmsgs: recvmsgs(0x6f9080): Processing valid message... // __nlmsg_alloc: msg 0x6fe1d8: Allocated new message, maxlen=1836 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1836 // .type = 16 <genl/family::nlctrl> // .flags = 0 <> // .seq = 1425769691 // .port = 2568 // [GENERIC NETLINK HEADER] 4 octets // .cmd = 1 // .version = 2 // .unused = 0 // [ATTR 02] 8 octets // 6e 6c 38 30 32 31 31 00 nl80211. // [ATTR 01] 2 octets // 16 00 .. // [PADDING] 2 octets // 00 00 .. // [ATTR 03] 4 octets // 01 00 00 00 .... // [ATTR 04] 4 octets // 00 00 00 00 .... // [ATTR 05] 4 octets // d5 00 00 00 .... // [ATTR 06] 1640 octets // 14 00 01 00 08 00 01 00 01 00 00 00 08 00 02 00 ................ // <trimmed> // 08 00 02 00 0b 00 00 00 ........ // [ATTR 07] 124 octets // 18 00 01 00 08 00 02 00 03 00 00 00 0b 00 01 00 ................ // 63 6f 6e 66 69 67 00 00 18 00 02 00 08 00 02 00 config.......... // 04 00 00 00 09 00 01 00 73 63 61 6e 00 00 00 00 ........scan.... // 1c 00 03 00 08 00 02 00 05 00 00 00 0f 00 01 00 ................ // 72 65 67 75 6c 61 74 6f 72 79 00 00 18 00 04 00 regulatory...... // 08 00 02 00 06 00 00 00 09 00 01 00 6d 6c 6d 65 ............mlme // 00 00 00 00 18 00 05 00 08 00 02 00 07 00 00 00 ................ // 0b 00 01 00 76 65 6e 64 6f 72 00 00 ....vendor.. // --------------------------- END NETLINK MESSAGE --------------------------- // nlmsg_free: Returned message reference 0x6fe1d8, 0 remaining // nlmsg_free: msg 0x6fe1d8: Freed // recvmsgs: Attempting to read from 0x6f9080 // recvmsgs: recvmsgs(0x6f9080): Read 36 bytes // recvmsgs: recvmsgs(0x6f9080): Processing valid message... // __nlmsg_alloc: msg 0x6fe1d8: Allocated new message, maxlen=36 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 36 // .type = 2 <ERROR> // .flags = 0 <> // .seq = 1425769691 // .port = 2568 // [ERRORMSG] 20 octets // .error = 0 "Success" // [ORIGINAL MESSAGE] 16 octets // __nlmsg_alloc: msg 0x6fe2b8: Allocated new message, maxlen=4096 // .nlmsg_len = 16 // .type = 16 <0x10> // .flags = 5 <REQUEST,ACK> // .seq = 1425769691 // .port = 2568 // nlmsg_free: Returned message reference 0x6fe2b8, 0 remaining // nlmsg_free: msg 0x6fe2b8: Freed // --------------------------- END NETLINK MESSAGE --------------------------- // recvmsgs: recvmsgs(0x6f9080): Increased expected sequence number to 1425769692 // nlmsg_free: Returned message reference 0x6fe1d8, 0 remaining // nlmsg_free: msg 0x6fe1d8: Freed // nlmsg_free: Returned message reference 0x6f9110, 0 remaining // nlmsg_free: msg 0x6f9110: Freed // nl_object_put: Returned object reference 0x6f90b8, 0 remaining // nl_object_free: Freed object 0x6f90b8 // 22 == driver_id // nl_cache_mngt_unregister: Unregistered cache operations genl/family """ del log[:] sk = nl_socket_alloc() assert 0 == genl_connect(sk) assert not log assert 20 <= genl_ctrl_resolve(sk, b'nl80211') nl_socket_free(sk) assert match('nl_object_alloc: Allocated new object 0x[a-f0-9]+', log, True) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match( 'nlmsg_put: msg 0x[a-f0-9]+: Added netlink header type=16, flags=0, pid=0, seq=0', log, True) assert match( 'nlmsg_reserve: msg 0x[a-f0-9]+: Reserved 4 \(4\) bytes, pad=4, nlmsg_len=20', log, True) assert match( 'genlmsg_put: msg 0x[a-f0-9]+: Added generic netlink header cmd=3 version=1', log, True) assert match( 'nla_reserve: msg 0x[a-f0-9]+: attr <0x[a-f0-9]+> 2: Reserved 12 \(8\) bytes at offset \+4 nlmsg_len=32', log, True) assert match( 'nla_put: msg 0x[a-f0-9]+: attr <0x[a-f0-9]+> 2: Wrote 8 bytes at offset \+4', log, True) assert match('nl_msg_out_handler_debug: -- Debug: Sent Message:', log) assert match( 'nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = 32', log) assert match('print_hdr: .type = 16 <genl/family::nlctrl>', log) assert match('print_hdr: .flags = 5 <REQUEST,ACK>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_genl_hdr: [GENERIC NETLINK HEADER] 4 octets', log) assert match('print_genl_hdr: .cmd = 3', log) assert match('print_genl_hdr: .version = 1', log) assert match('print_genl_hdr: .unused = 0', log) assert match('dump_attrs: [ATTR 02] 8 octets', log) assert match( 'dump_hex: 6e 6c 38 30 32 31 31 00 nl80211.', log) assert match( 'nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('nl_sendmsg: sent 32 bytes', log) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{3,} bytes', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=\d{3,}', log, True) assert match('nl_msg_in_handler_debug: -- Debug: Received Message:', log) assert match( 'nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = \d{3,}', log, True) assert match('print_hdr: .type = 16 <genl/family::nlctrl>', log) assert match('print_hdr: .flags = 0 <>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_genl_hdr: [GENERIC NETLINK HEADER] 4 octets', log) assert match('print_genl_hdr: .cmd = 1', log) assert match('print_genl_hdr: .version = 2', log) assert match('print_genl_hdr: .unused = 0', log) assert match('dump_attrs: [ATTR 02] 8 octets', log) assert match( 'dump_hex: 6e 6c 38 30 32 31 31 00 nl80211.', log) assert match('dump_attrs: [ATTR 01] 2 octets', log) assert match( 'dump_hex: .. 00 ..', log, True) assert match('dump_attrs: [PADDING] 2 octets', log) assert match( 'dump_hex: 00 00 ..', log) assert match('dump_attrs: [ATTR 03] 4 octets', log) assert match( 'dump_hex: 01 00 00 00 ....', log) assert match('dump_attrs: [ATTR 04] 4 octets', log) assert match( 'dump_hex: 00 00 00 00 ....', log) assert match('dump_attrs: [ATTR 05] 4 octets', log) assert match( 'dump_hex: .. 00 00 00 ....', log, True) assert match('dump_attrs: \[ATTR 06\] \d{4,} octets', log, True) assert match( 'dump_hex: 14 00 01 00 08 00 01 00 01 00 00 00 08 00 02 00 ................', log) # Done testing this payload. Too big. for line in log: if line.startswith('dump_hex'): continue rem = log.index(line) assert 20 < rem # At least check that there were a lot of log statements skipped. log = log[rem:] break assert match('dump_attrs: \[ATTR 07\] \d{3,} octets', log, True) assert match( 'dump_hex: 18 00 01 00 08 00 02 00 .. 00 00 00 0b 00 01 00 ................', log, True) assert match( 'dump_hex: 63 6f 6e 66 69 67 00 00 18 00 02 00 08 00 02 00 config..........', log) assert match( 'dump_hex: .. 00 00 00 09 00 01 00 73 63 61 6e 00 00 00 00 ........scan....', log, True) assert match( 'dump_hex: 1c 00 03 00 08 00 02 00 .. 00 00 00 0f 00 01 00 ................', log, True) assert match( 'dump_hex: 72 65 67 75 6c 61 74 6f 72 79 00 00 18 00 04 00 regulatory......', log) assert match( 'dump_hex: 08 00 02 00 .. 00 00 00 09 00 01 00 6d 6c 6d 65 ............mlme', log, True) rem = log.index( 'nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------' ) log = log[rem:] assert match( 'nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read 36 bytes', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=36', log, True) assert match('nl_msg_in_handler_debug: -- Debug: Received Message:', log) assert match( 'nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = 36', log) assert match('print_hdr: .type = 2 <ERROR>', log) assert match('print_hdr: .flags = 0 <>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('dump_error_msg: [ERRORMSG] 20 octets', log) assert match('dump_error_msg: .error = 0 "Success"', log) assert match('dump_error_msg: [ORIGINAL MESSAGE] 16 octets', log) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match('print_hdr: .nlmsg_len = 16', log) assert match('print_hdr: .type = 16 <0x[a-f0-9]+>', log, True) assert match('print_hdr: .flags = 5 <REQUEST,ACK>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match( 'nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Increased expected sequence number to \d{10}', log, True) assert not log
def test_genl_ctrl_resolve(log): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && NLDBG=4 NLCB=debug ./a.out #include <netlink/msg.h> int main() { struct nl_sock *sk = nl_socket_alloc(); printf("%d == genl_connect(sk)\n", genl_connect(sk)); int driver_id = genl_ctrl_resolve(sk, "nl80211"); printf("%d == driver_id\n", driver_id); nl_socket_free(sk); return 0; } // Expected output (trimmed): // nl_cache_mngt_register: Registered cache operations genl/family // 0 == genl_connect(sk) // nl_object_alloc: Allocated new object 0x6f90b8 // __nlmsg_alloc: msg 0x6f9110: Allocated new message, maxlen=4096 // nlmsg_put: msg 0x6f9110: Added netlink header type=16, flags=0, pid=0, seq=0 // nlmsg_reserve: msg 0x6f9110: Reserved 4 (4) bytes, pad=4, nlmsg_len=20 // genlmsg_put: msg 0x6f9110: Added generic netlink header cmd=3 version=1 // nla_reserve: msg 0x6f9110: attr <0x6f9164> 2: Reserved 12 (8) bytes at offset +4 nlmsg_len=32 // nla_put: msg 0x6f9110: attr <0x6f9164> 2: Wrote 8 bytes at offset +4 // -- Debug: Sent Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 32 // .type = 16 <genl/family::nlctrl> // .flags = 5 <REQUEST,ACK> // .seq = 1425769691 // .port = 2568 // [GENERIC NETLINK HEADER] 4 octets // .cmd = 3 // .version = 1 // .unused = 0 // [ATTR 02] 8 octets // 6e 6c 38 30 32 31 31 00 nl80211. // --------------------------- END NETLINK MESSAGE --------------------------- // nl_sendmsg: sent 32 bytes // recvmsgs: Attempting to read from 0x6f9080 // recvmsgs: recvmsgs(0x6f9080): Read 1836 bytes // recvmsgs: recvmsgs(0x6f9080): Processing valid message... // __nlmsg_alloc: msg 0x6fe1d8: Allocated new message, maxlen=1836 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1836 // .type = 16 <genl/family::nlctrl> // .flags = 0 <> // .seq = 1425769691 // .port = 2568 // [GENERIC NETLINK HEADER] 4 octets // .cmd = 1 // .version = 2 // .unused = 0 // [ATTR 02] 8 octets // 6e 6c 38 30 32 31 31 00 nl80211. // [ATTR 01] 2 octets // 16 00 .. // [PADDING] 2 octets // 00 00 .. // [ATTR 03] 4 octets // 01 00 00 00 .... // [ATTR 04] 4 octets // 00 00 00 00 .... // [ATTR 05] 4 octets // d5 00 00 00 .... // [ATTR 06] 1640 octets // 14 00 01 00 08 00 01 00 01 00 00 00 08 00 02 00 ................ // <trimmed> // 08 00 02 00 0b 00 00 00 ........ // [ATTR 07] 124 octets // 18 00 01 00 08 00 02 00 03 00 00 00 0b 00 01 00 ................ // 63 6f 6e 66 69 67 00 00 18 00 02 00 08 00 02 00 config.......... // 04 00 00 00 09 00 01 00 73 63 61 6e 00 00 00 00 ........scan.... // 1c 00 03 00 08 00 02 00 05 00 00 00 0f 00 01 00 ................ // 72 65 67 75 6c 61 74 6f 72 79 00 00 18 00 04 00 regulatory...... // 08 00 02 00 06 00 00 00 09 00 01 00 6d 6c 6d 65 ............mlme // 00 00 00 00 18 00 05 00 08 00 02 00 07 00 00 00 ................ // 0b 00 01 00 76 65 6e 64 6f 72 00 00 ....vendor.. // --------------------------- END NETLINK MESSAGE --------------------------- // nlmsg_free: Returned message reference 0x6fe1d8, 0 remaining // nlmsg_free: msg 0x6fe1d8: Freed // recvmsgs: Attempting to read from 0x6f9080 // recvmsgs: recvmsgs(0x6f9080): Read 36 bytes // recvmsgs: recvmsgs(0x6f9080): Processing valid message... // __nlmsg_alloc: msg 0x6fe1d8: Allocated new message, maxlen=36 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 36 // .type = 2 <ERROR> // .flags = 0 <> // .seq = 1425769691 // .port = 2568 // [ERRORMSG] 20 octets // .error = 0 "Success" // [ORIGINAL MESSAGE] 16 octets // __nlmsg_alloc: msg 0x6fe2b8: Allocated new message, maxlen=4096 // .nlmsg_len = 16 // .type = 16 <0x10> // .flags = 5 <REQUEST,ACK> // .seq = 1425769691 // .port = 2568 // nlmsg_free: Returned message reference 0x6fe2b8, 0 remaining // nlmsg_free: msg 0x6fe2b8: Freed // --------------------------- END NETLINK MESSAGE --------------------------- // recvmsgs: recvmsgs(0x6f9080): Increased expected sequence number to 1425769692 // nlmsg_free: Returned message reference 0x6fe1d8, 0 remaining // nlmsg_free: msg 0x6fe1d8: Freed // nlmsg_free: Returned message reference 0x6f9110, 0 remaining // nlmsg_free: msg 0x6f9110: Freed // nl_object_put: Returned object reference 0x6f90b8, 0 remaining // nl_object_free: Freed object 0x6f90b8 // 22 == driver_id // nl_cache_mngt_unregister: Unregistered cache operations genl/family """ del log[:] sk = nl_socket_alloc() assert 0 == genl_connect(sk) assert not log assert 20 <= genl_ctrl_resolve(sk, b'nl80211') nl_socket_free(sk) assert match('nl_object_alloc: Allocated new object 0x[a-f0-9]+', log, True) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match('nlmsg_put: msg 0x[a-f0-9]+: Added netlink header type=16, flags=0, pid=0, seq=0', log, True) assert match('nlmsg_reserve: msg 0x[a-f0-9]+: Reserved 4 \(4\) bytes, pad=4, nlmsg_len=20', log, True) assert match('genlmsg_put: msg 0x[a-f0-9]+: Added generic netlink header cmd=3 version=1', log, True) assert match( 'nla_reserve: msg 0x[a-f0-9]+: attr <0x[a-f0-9]+> 2: Reserved 12 \(8\) bytes at offset \+4 nlmsg_len=32', log, True) assert match('nla_put: msg 0x[a-f0-9]+: attr <0x[a-f0-9]+> 2: Wrote 8 bytes at offset \+4', log, True) assert match('nl_msg_out_handler_debug: -- Debug: Sent Message:', log) assert match('nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = 32', log) assert match('print_hdr: .type = 16 <genl/family::nlctrl>', log) assert match('print_hdr: .flags = 5 <REQUEST,ACK>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_genl_hdr: [GENERIC NETLINK HEADER] 4 octets', log) assert match('print_genl_hdr: .cmd = 3', log) assert match('print_genl_hdr: .version = 1', log) assert match('print_genl_hdr: .unused = 0', log) assert match('dump_attrs: [ATTR 02] 8 octets', log) assert match('dump_hex: 6e 6c 38 30 32 31 31 00 nl80211.', log) assert match('nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('nl_sendmsg: sent 32 bytes', log) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{3,} bytes', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=\d{3,}', log, True) assert match('nl_msg_in_handler_debug: -- Debug: Received Message:', log) assert match('nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = \d{3,}', log, True) assert match('print_hdr: .type = 16 <genl/family::nlctrl>', log) assert match('print_hdr: .flags = 0 <>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_genl_hdr: [GENERIC NETLINK HEADER] 4 octets', log) assert match('print_genl_hdr: .cmd = 1', log) assert match('print_genl_hdr: .version = 2', log) assert match('print_genl_hdr: .unused = 0', log) assert match('dump_attrs: [ATTR 02] 8 octets', log) assert match('dump_hex: 6e 6c 38 30 32 31 31 00 nl80211.', log) assert match('dump_attrs: [ATTR 01] 2 octets', log) assert match('dump_hex: .. 00 ..', log, True) assert match('dump_attrs: [PADDING] 2 octets', log) assert match('dump_hex: 00 00 ..', log) assert match('dump_attrs: [ATTR 03] 4 octets', log) assert match('dump_hex: 01 00 00 00 ....', log) assert match('dump_attrs: [ATTR 04] 4 octets', log) assert match('dump_hex: 00 00 00 00 ....', log) assert match('dump_attrs: [ATTR 05] 4 octets', log) assert match('dump_hex: .. 00 00 00 ....', log, True) assert match('dump_attrs: \[ATTR 06\] \d{4,} octets', log, True) assert match('dump_hex: 14 00 01 00 08 00 01 00 01 00 00 00 08 00 02 00 ................', log) # Done testing this payload. Too big. for line in log: if line.startswith('dump_hex'): continue rem = log.index(line) assert 20 < rem # At least check that there were a lot of log statements skipped. log = log[rem:] break assert match('dump_attrs: \[ATTR 07\] \d{3,} octets', log, True) assert match('dump_hex: 18 00 01 00 08 00 02 00 .. 00 00 00 0b 00 01 00 ................', log, True) assert match('dump_hex: 63 6f 6e 66 69 67 00 00 18 00 02 00 08 00 02 00 config..........', log) assert match('dump_hex: .. 00 00 00 09 00 01 00 73 63 61 6e 00 00 00 00 ........scan....', log, True) assert match('dump_hex: 1c 00 03 00 08 00 02 00 .. 00 00 00 0f 00 01 00 ................', log, True) assert match('dump_hex: 72 65 67 75 6c 61 74 6f 72 79 00 00 18 00 04 00 regulatory......', log) assert match('dump_hex: 08 00 02 00 .. 00 00 00 09 00 01 00 6d 6c 6d 65 ............mlme', log, True) rem = log.index('nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------') log = log[rem:] assert match('nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read 36 bytes', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=36', log, True) assert match('nl_msg_in_handler_debug: -- Debug: Received Message:', log) assert match('nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = 36', log) assert match('print_hdr: .type = 2 <ERROR>', log) assert match('print_hdr: .flags = 0 <>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('dump_error_msg: [ERRORMSG] 20 octets', log) assert match('dump_error_msg: .error = 0 "Success"', log) assert match('dump_error_msg: [ORIGINAL MESSAGE] 16 octets', log) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match('print_hdr: .nlmsg_len = 16', log) assert match('print_hdr: .type = 16 <0x[a-f0-9]+>', log, True) assert match('print_hdr: .flags = 5 <REQUEST,ACK>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Increased expected sequence number to \d{10}', log, True) assert not log
def channel_hopper(): global count # Get the index of the interface pack = struct.pack('16sI', interface, 0) sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: info = struct.unpack('16sI', fcntl.ioctl(sk.fileno(), 0x8933, pack)) except (OSError, IOError): error('wireless interface {0} does not exist.'.format(interface)) return -1 finally: sk.close() if_index = int(info[1]) # Open a socket to the kernel sk = nl_socket_alloc() ret = genl_connect(sk) if ret < 0: reason = errmsg[abs(ret)] error('genl_connect() failed: {0} ({1})'.format(ret, reason)) return -1 # Now get the nl80211 driver ID driver_id = genl_ctrl_resolve(sk, b'nl80211') if driver_id < 0: reason = errmsg[abs(driver_id)] error('genl_ctrl_resolve() failed: {0} ({1})'.format( driver_id, reason)) return -1 # Iterate over channels using the corresponding dwell time supported_channels = [x for x in channels if x not in unsupported_channels] for ch in supported_channels: if not sniffing: break # Set new channel msg = nlmsg_alloc() genlmsg_put(msg, 0, 0, driver_id, 0, 0, nl80211.NL80211_CMD_SET_CHANNEL, 0) nla_put_u32(msg, nl80211.NL80211_ATTR_IFINDEX, if_index) nla_put_u32(msg, nl80211.NL80211_ATTR_WIPHY_FREQ, channel_to_frequency(ch)) nla_put_u32(msg, nl80211.NL80211_ATTR_WIPHY_CHANNEL_TYPE, nl80211.NL80211_CHAN_WIDTH_20) if nl_send_auto(sk, msg) < 0: unsupported_channels.add(ch) time.sleep(0.02) else: count = 0 time.sleep(dwelltimes[ch]) if count == 0: dwelltimes[ch] = mindwelltime else: dwelltimes[ch] = maxdwelltime return 0