Example #1
0
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
Example #3
0
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
Example #4
0
    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 {}
Example #5
0
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))
Example #6
0
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')
Example #7
0
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))
Example #9
0
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
Example #10
0
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