Exemple #1
0
def genlmsg_valid_hdr(nlh, hdrlen):
    """Validate Generic Netlink message headers.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/genl.c#L117

    Verifies the integrity of the Netlink and Generic Netlink headers by enforcing the following requirements:
    - Valid Netlink message header (`nlmsg_valid_hdr()`)
    - Presence of a complete Generic Netlink header
    - At least `hdrlen` bytes of payload included after the generic Netlink header.

    Positional arguments:
    nlh -- Netlink message header (nlmsghdr class instance).
    hdrlen -- length of user header (integer).

    Returns:
    True if the headers are valid or False if not.
    """
    if not nlmsg_valid_hdr(nlh, GENL_HDRLEN):
        return False

    ghdr = genlmsghdr(nlmsg_data(nlh))
    if genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen):
        return False

    return True
Exemple #2
0
def genlmsg_put(msg, port, seq, family, hdrlen, flags, cmd, version):
    """Add Generic Netlink headers to Netlink message.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/genl.c#L348

    Calls nlmsg_put() on the specified message object to reserve space for the Netlink header, the Generic Netlink
    header, and a user header of specified length. Fills out the header fields with the specified parameters.

    Positional arguments:
    msg -- Netlink message object (nl_msg class instance).
    port -- Netlink port or NL_AUTO_PORT (c_uint32).
    seq -- sequence number of message or NL_AUTO_SEQ (c_uint32).
    family -- numeric family identifier (integer).
    hdrlen -- length of user header (integer).
    flags -- additional Netlink message flags (integer).
    cmd -- numeric command identifier (c_uint8).
    version -- interface version (c_uint8).

    Returns:
    bytearray starting at user header or None if an error occurred.
    """
    hdr = genlmsghdr(cmd=cmd, version=version)
    nlh = nlmsg_put(msg, port, seq, family, GENL_HDRLEN + hdrlen, flags)
    if nlh is None:
        return None
    nlmsg_data(nlh)[:hdr.SIZEOF] = hdr.bytearray[:hdr.SIZEOF]
    _LOGGER.debug('msg 0x%x: Added generic netlink header cmd=%d version=%d',
                  id(msg), cmd, version)
    return bytearray_ptr(nlmsg_data(nlh), GENL_HDRLEN)
Exemple #3
0
def genlmsg_put(msg, port, seq, family, hdrlen, flags, cmd, version):
    """Add Generic Netlink headers to Netlink message.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/genl.c#L348

    Calls nlmsg_put() on the specified message object to reserve space for the Netlink header, the Generic Netlink
    header, and a user header of specified length. Fills out the header fields with the specified parameters.

    Positional arguments:
    msg -- Netlink message object (nl_msg class instance).
    port -- Netlink port or NL_AUTO_PORT (c_uint32).
    seq -- sequence number of message or NL_AUTO_SEQ (c_uint32).
    family -- numeric family identifier (integer).
    hdrlen -- length of user header (integer).
    flags -- additional Netlink message flags (integer).
    cmd -- numeric command identifier (c_uint8).
    version -- interface version (c_uint8).

    Returns:
    bytearray starting at user header or None if an error occurred.
    """
    hdr = genlmsghdr(cmd=cmd, version=version)
    nlh = nlmsg_put(msg, port, seq, family, GENL_HDRLEN + hdrlen, flags)
    if nlh is None:
        return None
    nlmsg_data(nlh)[:hdr.SIZEOF] = hdr.bytearray[:hdr.SIZEOF]
    _LOGGER.debug('msg 0x%x: Added generic netlink header cmd=%d version=%d', id(msg), cmd, version)
    return bytearray_ptr(nlmsg_data(nlh), GENL_HDRLEN)
Exemple #4
0
def callback_dump(msg, results):
    """Here is where SSIDs and their data is decoded from the binary data sent by the kernel.

    This function is called once per SSID. Everything in `msg` pertains to just one SSID.

    Positional arguments:
    msg -- nl_msg class instance containing the data sent by the kernel.
    results -- dictionary to populate with parsed data.
    """
    bss = dict()  # To be filled by nla_parse_nested().

    # First we must parse incoming data into manageable chunks and check for errors.
    gnlh = genlmsghdr(nlmsg_data(nlmsg_hdr(msg)))
    tb = dict((i, None) for i in range(nl80211.NL80211_ATTR_MAX + 1))
    nla_parse(tb, nl80211.NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), None)
    if not tb[nl80211.NL80211_ATTR_BSS]:
        print('WARNING: BSS info missing for an access point.')
        return libnl.handlers.NL_SKIP
    if nla_parse_nested(bss, nl80211.NL80211_BSS_MAX, tb[nl80211.NL80211_ATTR_BSS], bss_policy):
        print('WARNING: Failed to parse nested attributes for an access point!')
        return libnl.handlers.NL_SKIP
    if not bss[nl80211.NL80211_BSS_BSSID]:
        print('WARNING: No BSSID detected for an access point!')
        return libnl.handlers.NL_SKIP
    if not bss[nl80211.NL80211_BSS_INFORMATION_ELEMENTS]:
        print('WARNING: No additional information available for an access point!')
        return libnl.handlers.NL_SKIP

    # Further parse and then store. Overwrite existing data for BSSID if scan is run multiple times.
    bss_parsed = parse_bss(bss)
    results[bss_parsed['bssid']] = bss_parsed
    return libnl.handlers.NL_SKIP
Exemple #5
0
    def _callback_dump(self, msg, results):
        # Here is where SSIDs and their data is decoded from the binary data
        # sent by the kernel. This function is called once per SSID. Everything
        # in `msg` pertains to just one SSID.
        #
        # Positional arguments:
        # msg -- nl_msg class instance containing the data sent by the kernel.
        # results -- dictionary to populate with parsed data.
        bss = dict()  # To be filled by nla_parse_nested().

        # First we must parse incoming data into manageable chunks and check for errors.
        gnlh = genlmsghdr(nlmsg_data(nlmsg_hdr(msg)))
        tb = dict((i, None) for i in range(nl80211.NL80211_ATTR_MAX + 1))
        nla_parse(tb, nl80211.NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), None)
        if not tb[nl80211.NL80211_ATTR_BSS]:
            logger.warning('BSS info missing for an access point.')
            return libnl.handlers.NL_SKIP
        if nla_parse_nested(bss, nl80211.NL80211_BSS_MAX,
                            tb[nl80211.NL80211_ATTR_BSS], bss_policy):
            logger.warning(
                'Failed to parse nested attributes for an access point!')
            return libnl.handlers.NL_SKIP
        if not bss[nl80211.NL80211_BSS_BSSID]:
            logger.warning('No BSSID detected for an access point!')
            return libnl.handlers.NL_SKIP
        if not bss[nl80211.NL80211_BSS_INFORMATION_ELEMENTS]:
            logger.warning(
                'No additional information available for an access point!')
            return libnl.handlers.NL_SKIP

        # Further parse and then store. Overwrite existing data for BSSID if scan is run multiple times.
        bss_parsed = parse_bss(bss)
        results[bss_parsed['bssid']] = bss_parsed
        return libnl.handlers.NL_SKIP
Exemple #6
0
def genlmsg_parse(nlh, hdrlen, tb, maxtype, policy):
    """Parse Generic Netlink message including attributes.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/genl.c#L191

    Verifies the validity of the Netlink and Generic Netlink headers using genlmsg_valid_hdr() and calls nla_parse() on
    the message payload to parse eventual attributes.

    Positional arguments:
    nlh -- Netlink message header (nlmsghdr class instance).
    hdrlen -- length of user header (integer).
    tb -- empty dict, to be updated with nlattr class instances to store parsed attributes.
    maxtype -- maximum attribute id expected (integer).
    policy -- dictionary of nla_policy class instances as values, with nla types as keys.

    Returns:
    0 on success or a negative error code.
    """
    if not genlmsg_valid_hdr(nlh, hdrlen):
        return -NLE_MSG_TOOSHORT

    ghdr = genlmsghdr(nlmsg_data(nlh))
    return int(
        nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
                  genlmsg_attrlen(ghdr, hdrlen), policy))
Exemple #7
0
def genlmsg_valid_hdr(nlh, hdrlen):
    """Validate Generic Netlink message headers.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/genl.c#L117

    Verifies the integrity of the Netlink and Generic Netlink headers by enforcing the following requirements:
    - Valid Netlink message header (`nlmsg_valid_hdr()`)
    - Presence of a complete Generic Netlink header
    - At least `hdrlen` bytes of payload included after the generic Netlink header.

    Positional arguments:
    nlh -- Netlink message header (nlmsghdr class instance).
    hdrlen -- length of user header (integer).

    Returns:
    True if the headers are valid or False if not.
    """
    if not nlmsg_valid_hdr(nlh, GENL_HDRLEN):
        return False

    ghdr = genlmsghdr(nlmsg_data(nlh))
    if genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen):
        return False

    return True
Exemple #8
0
def dump_callback(msg, _):

    gnlh = genlmsghdr(nlmsg_data(nlmsg_hdr(msg)))
    tb = dict((i, None) for i in range(NCSI_ATTR_MAX + 1))
    nla_parse(tb, NCSI_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
              genlmsg_attrlen(gnlh, 0), None)

    print(tb)
    return NL_SKIP
Exemple #9
0
    def callback_trigger(self, msg, arg):
        gnlh = genlmsghdr(nlmsg_data(nlmsg_hdr(msg)))

        tb = dict((i, None) for i in range(10 + 1))
        nla_parse(tb, nl80211.NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), None)
        if tb.get(NL_CMD_RECOVERY_MSG):
            self.recovery = True

        return libnl.handlers.NL_STOP
def callback(msg, has_printed):
    """Callback function called by libnl upon receiving messages from the kernel.

    Positional arguments:
    msg -- nl_msg class instance containing the data sent by the kernel.
    has_printed -- simple pseudo boolean (if list is empty) to keep track of when to print emtpy lines.

    Returns:
    An integer, value of NL_SKIP. It tells libnl to stop calling other callbacks for this message and proceed with
    processing the next kernel message.
    """
    table = AsciiTable([['Data Type', 'Data Value']])
    # First convert `msg` into something more manageable.
    gnlh = genlmsghdr(nlmsg_data(nlmsg_hdr(msg)))

    # Partially parse the raw binary data and place them in the `tb` dictionary.
    tb = dict(
        (i, None)
        for i in range(nl80211.NL80211_ATTR_MAX +
                       1))  # Need to populate dict with all possible keys.
    nla_parse(tb, nl80211.NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
              genlmsg_attrlen(gnlh, 0), None)

    # Now it's time to grab the juicy data!
    if tb[nl80211.NL80211_ATTR_IFNAME]:
        table.title = nla_get_string(
            tb[nl80211.NL80211_ATTR_IFNAME]).decode('ascii')
    else:
        table.title = 'Unnamed Interface'

    if tb[nl80211.NL80211_ATTR_WIPHY]:
        wiphy_num = nla_get_u32(tb[nl80211.NL80211_ATTR_WIPHY])
        wiphy = ('wiphy {0}'
                 if OPTIONS['<interface>'] else 'phy#{0}').format(wiphy_num)
        table.table_data.append(['NL80211_ATTR_WIPHY', wiphy])

    if tb[nl80211.NL80211_ATTR_MAC]:
        mac_address = ':'.join(
            format(x, '02x')
            for x in nla_data(tb[nl80211.NL80211_ATTR_MAC])[:6])
        table.table_data.append(['NL80211_ATTR_MAC', mac_address])

    if tb[nl80211.NL80211_ATTR_IFINDEX]:
        table.table_data.append([
            'NL80211_ATTR_IFINDEX',
            str(nla_get_u32(tb[nl80211.NL80211_ATTR_IFINDEX]))
        ])

    # Print all data.
    if has_printed:
        print()
    else:
        has_printed.append(True)
    print(table.table)
    return NL_SKIP
Exemple #11
0
def print_genl_hdr(ofd, start):
    """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/msg.c#L821.

    Positional arguments:
    ofd -- function to call with arguments similar to `logging.debug`.
    start -- bytearray() or bytearray_ptr() instance.
    """
    ghdr = genlmsghdr(start)
    ofd('  [GENERIC NETLINK HEADER] %d octets', GENL_HDRLEN)
    ofd('    .cmd = %d', ghdr.cmd)
    ofd('    .version = %d', ghdr.version)
    ofd('    .unused = %#d', ghdr.reserved)
Exemple #12
0
def callback_trigger(msg, arg):
    """Called when the kernel is done scanning. Only signals if it was successful or if it failed. No other data.

    Positional arguments:
    msg -- nl_msg class instance containing the data sent by the kernel.
    arg -- mutable integer (ctypes.c_int()) to update with results.

    Returns:
    An integer, value of NL_SKIP. It tells libnl to stop calling other callbacks for this message and proceed with
    processing the next kernel message.
    """
    gnlh = genlmsghdr(nlmsg_data(nlmsg_hdr(msg)))
    if gnlh.cmd == nl80211.NL80211_CMD_SCAN_ABORTED:
        arg.value = 1  # The scan was aborted for some reason.
    elif gnlh.cmd == nl80211.NL80211_CMD_NEW_SCAN_RESULTS:
        arg.value = 0  # The scan completed successfully. `callback_dump` will collect the results later.
    return libnl.handlers.NL_SKIP
Exemple #13
0
def callback_trigger(msg, arg):
    """Called when the kernel is done scanning. Only signals if it was successful or if it failed. No other data.

    Positional arguments:
    msg -- nl_msg class instance containing the data sent by the kernel.
    arg -- mutable integer (ctypes.c_int()) to update with results.

    Returns:
    An integer, value of NL_SKIP. It tells libnl to stop calling other callbacks for this message and proceed with
    processing the next kernel message.
    """
    gnlh = genlmsghdr(nlmsg_data(nlmsg_hdr(msg)))
    if gnlh.cmd == nl80211.NL80211_CMD_SCAN_ABORTED:
        arg.value = 1  # The scan was aborted for some reason.
    elif gnlh.cmd == nl80211.NL80211_CMD_NEW_SCAN_RESULTS:
        arg.value = 0  # The scan completed successfully. `callback_dump` will collect the results later.
    return libnl.handlers.NL_SKIP
def callback(msg, has_printed):
    """Callback function called by libnl upon receiving messages from the kernel.

    Positional arguments:
    msg -- nl_msg class instance containing the data sent by the kernel.
    has_printed -- simple pseudo boolean (if list is empty) to keep track of when to print emtpy lines.

    Returns:
    An integer, value of NL_SKIP. It tells libnl to stop calling other callbacks for this message and proceed with
    processing the next kernel message.
    """
    table = AsciiTable([['Data Type', 'Data Value']])
    # First convert `msg` into something more manageable.
    gnlh = genlmsghdr(nlmsg_data(nlmsg_hdr(msg)))

    # Partially parse the raw binary data and place them in the `tb` dictionary.
    tb = dict((i, None) for i in range(nl80211.NL80211_ATTR_MAX + 1))  # Need to populate dict with all possible keys.
    nla_parse(tb, nl80211.NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), None)

    # Now it's time to grab the juicy data!
    if tb[nl80211.NL80211_ATTR_IFNAME]:
        table.title = nla_get_string(tb[nl80211.NL80211_ATTR_IFNAME]).decode('ascii')
    else:
        table.title = 'Unnamed Interface'

    if tb[nl80211.NL80211_ATTR_WIPHY]:
        wiphy_num = nla_get_u32(tb[nl80211.NL80211_ATTR_WIPHY])
        wiphy = ('wiphy {0}' if OPTIONS['<interface>'] else 'phy#{0}').format(wiphy_num)
        table.table_data.append(['NL80211_ATTR_WIPHY', wiphy])

    if tb[nl80211.NL80211_ATTR_MAC]:
        mac_address = ':'.join(format(x, '02x') for x in nla_data(tb[nl80211.NL80211_ATTR_MAC])[:6])
        table.table_data.append(['NL80211_ATTR_MAC', mac_address])

    if tb[nl80211.NL80211_ATTR_IFINDEX]:
        table.table_data.append(['NL80211_ATTR_IFINDEX', str(nla_get_u32(tb[nl80211.NL80211_ATTR_IFINDEX]))])

    # Print all data.
    if has_printed:
        print()
    else:
        has_printed.append(True)
    print(table.table)
    return NL_SKIP
Exemple #15
0
def genl_send_simple(sk, family, cmd, version, flags):
    """Send a Generic Netlink message consisting only of a header.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/genl.c#L84

    This function is a shortcut for sending a Generic Netlink message without any message payload. The message will only
    consist of the Netlink and Generic Netlink headers. The header is constructed based on the specified parameters and
    passed on to nl_send_simple() to send it on the specified socket.

    Positional arguments:
    sk -- Generic Netlink socket (nl_sock class instance).
    family -- numeric family identifier (integer).
    cmd -- numeric command identifier (integer).
    version -- interface version (integer).
    flags -- additional Netlink message flags (integer).

    Returns:
    0 on success or a negative error code.
    """
    hdr = genlmsghdr(cmd=cmd, version=version)
    return int(nl_send_simple(sk, family, flags, hdr, hdr.SIZEOF))
Exemple #16
0
def genl_send_simple(sk, family, cmd, version, flags):
    """Send a Generic Netlink message consisting only of a header.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/genl.c#L84

    This function is a shortcut for sending a Generic Netlink message without any message payload. The message will only
    consist of the Netlink and Generic Netlink headers. The header is constructed based on the specified parameters and
    passed on to nl_send_simple() to send it on the specified socket.

    Positional arguments:
    sk -- Generic Netlink socket (nl_sock class instance).
    family -- numeric family identifier (integer).
    cmd -- numeric command identifier (integer).
    version -- interface version (integer).
    flags -- additional Netlink message flags (integer).

    Returns:
    0 on success or a negative error code.
    """
    hdr = genlmsghdr(cmd=cmd, version=version)
    return int(nl_send_simple(sk, family, flags, hdr, hdr.SIZEOF))
Exemple #17
0
def genlmsg_parse(nlh, hdrlen, tb, maxtype, policy):
    """Parse Generic Netlink message including attributes.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/genl.c#L191

    Verifies the validity of the Netlink and Generic Netlink headers using genlmsg_valid_hdr() and calls nla_parse() on
    the message payload to parse eventual attributes.

    Positional arguments:
    nlh -- Netlink message header (nlmsghdr class instance).
    hdrlen -- length of user header (integer).
    tb -- empty dict, to be updated with nlattr class instances to store parsed attributes.
    maxtype -- maximum attribute id expected (integer).
    policy -- dictionary of nla_policy class instances as values, with nla types as keys.

    Returns:
    0 on success or a negative error code.
    """
    if not genlmsg_valid_hdr(nlh, hdrlen):
        return -NLE_MSG_TOOSHORT

    ghdr = genlmsghdr(nlmsg_data(nlh))
    return int(nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen), genlmsg_attrlen(ghdr, hdrlen), policy))
    def _iface_callback(self, msg, _):
        # Callback function called by libnl upon receiving messages from the
        # kernel.
        #
        # Positional arguments:
        # msg -- nl_msg class instance containing the data sent by the kernel.
        #
        # Returns:
        # An integer, value of NL_SKIP. It tells libnl to stop calling other
        # callbacks for this message and proceed with processing the next kernel
        # message.
        # First convert `msg` into something more manageable.
        gnlh = genlmsghdr(nlmsg_data(nlmsg_hdr(msg)))

        # Partially parse the raw binary data and place them in the `tb`
        # dictionary. Need to populate dict with all possible keys.
        tb = dict((i, None) for i in range(nl80211.NL80211_ATTR_MAX + 1))
        nla_parse(tb, nl80211.NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), None)

        # Now it's time to grab the data, we start with the interface index as
        # universal identifier
        if tb[nl80211.NL80211_ATTR_IFINDEX]:
            if_index = nla_get_u32(tb[nl80211.NL80211_ATTR_IFINDEX])
        else:
            return NL_SKIP

        # Create new interface dict if this interface is not yet known
        if if_index in self.iface_data:
            iface_data = self.iface_data[if_index]
        else:
            iface_data = {}

        if tb[nl80211.NL80211_ATTR_IFNAME]:
            iface_data['name'] = nla_get_string(
                tb[nl80211.NL80211_ATTR_IFNAME]).decode('ascii')

        if tb[nl80211.NL80211_ATTR_IFTYPE]:
            iftype = nla_get_u32(tb[nl80211.NL80211_ATTR_IFTYPE])

            if iftype == nl80211.NL80211_IFTYPE_UNSPECIFIED:
                typestr = 'UNSPECIFIED'
            elif iftype == nl80211.NL80211_IFTYPE_ADHOC:
                typestr = 'ADHOC'
            elif iftype == nl80211.NL80211_IFTYPE_STATION:
                typestr = 'STATION'
            elif iftype == nl80211.NL80211_IFTYPE_AP:
                typestr = 'AP'
            elif iftype == nl80211.NL80211_IFTYPE_AP_VLAN:
                typestr = 'AP_VLAN'
            elif iftype == nl80211.NL80211_IFTYPE_WDS:
                typestr = 'WDS'
            elif iftype == nl80211.NL80211_IFTYPE_MONITOR:
                typestr = 'MONITOR'
            elif iftype == nl80211.NL80211_IFTYPE_MESH_POINT:
                typestr = 'MESH_POINT'
            elif iftype == nl80211.NL80211_IFTYPE_P2P_CLIENT:
                typestr = 'P2P_CLIENT'
            elif iftype == nl80211.NL80211_IFTYPE_P2P_GO:
                typestr = 'P2P_GO'
            elif iftype == nl80211.NL80211_IFTYPE_P2P_DEVICE:
                typestr = 'P2P_DEVICE'

            iface_data['type'] = typestr

        if tb[nl80211.NL80211_ATTR_WIPHY]:
            wiphy_num = nla_get_u32(tb[nl80211.NL80211_ATTR_WIPHY])
            iface_data['wiphy'] = 'phy#{0}'.format(wiphy_num)

        if tb[nl80211.NL80211_ATTR_MAC]:
            mac_raw = nla_data(tb[nl80211.NL80211_ATTR_MAC])[:6]
            mac_address = ':'.join(format(x, '02x') for x in mac_raw)
            iface_data['mac'] = mac_address
            if (gnlh.cmd == nl80211.NL80211_CMD_NEW_STATION
                    and if_index == self.if_idx):
                # This is the BSSID that we're currently associated to
                self.bssid = mac_address

        if tb[nl80211.NL80211_ATTR_GENERATION]:
            generation = nla_get_u32(tb[nl80211.NL80211_ATTR_GENERATION])
            # Do not overwrite the generation for excessively large values
            if generation < 100:
                iface_data['generation'] = generation

        if tb[nl80211.NL80211_ATTR_WIPHY_TX_POWER_LEVEL]:
            iface_data['tx_power'] = nla_get_u32(
                tb[nl80211.NL80211_ATTR_WIPHY_TX_POWER_LEVEL]) / 100  # mW

        if tb[nl80211.NL80211_ATTR_CHANNEL_WIDTH]:
            iface_data['ch_width'] = nla_get_u32(
                tb[nl80211.NL80211_ATTR_CHANNEL_WIDTH])

        if tb[nl80211.NL80211_ATTR_CENTER_FREQ1]:
            iface_data['frequency'] = nla_get_u32(
                tb[nl80211.NL80211_ATTR_CENTER_FREQ1])

        # Station infos
        if tb[nl80211.NL80211_ATTR_STA_INFO]:
            # Need to unpack the data
            sinfo = dict(
                (i, None) for i in range(nl80211.NL80211_STA_INFO_MAX))
            rinfo = dict(
                (i, None) for i in range(nl80211.NL80211_STA_INFO_TX_BITRATE))

            # Extract data
            nla_parse_nested(sinfo, nl80211.NL80211_STA_INFO_MAX,
                             tb[nl80211.NL80211_ATTR_STA_INFO], None)

            # Extract info about signal strength (= quality)
            if sinfo[nl80211.NL80211_STA_INFO_SIGNAL]:
                iface_data['signal'] = 100 + \
                    nla_get_u8(sinfo[nl80211.NL80211_STA_INFO_SIGNAL])
                # Compute quality (formula found in iwinfo_nl80211.c and largely
                # simplified)
                iface_data['quality'] = iface_data['signal'] + 110
                iface_data['quality_max'] = 70

            # Extract info about negotiated bitrate
            if sinfo[nl80211.NL80211_STA_INFO_TX_BITRATE]:
                nla_parse_nested(rinfo, nl80211.NL80211_RATE_INFO_MAX,
                                 sinfo[nl80211.NL80211_STA_INFO_TX_BITRATE],
                                 None)
                if rinfo[nl80211.NL80211_RATE_INFO_BITRATE]:
                    iface_data['bitrate'] = nla_get_u16(
                        rinfo[nl80211.NL80211_RATE_INFO_BITRATE]) / 10

        # BSS info
        if tb[nl80211.NL80211_ATTR_BSS]:
            # Need to unpack the data
            binfo = dict((i, None) for i in range(nl80211.NL80211_BSS_MAX))
            nla_parse_nested(binfo, nl80211.NL80211_BSS_MAX,
                             tb[nl80211.NL80211_ATTR_BSS], None)

            # Parse BSS section (if complete)
            try:
                bss = parse_bss(binfo)

                # Remove duplicated information blocks
                if 'beacon_ies' in bss:
                    del bss['beacon_ies']
                if 'information_elements' in bss:
                    del bss['information_elements']
                if 'supported_rates' in bss:
                    del bss['supported_rates']

                # Convert timedelta objects for later JSON encoding
                for prop in bss:
                    if isinstance(bss[prop], datetime.timedelta):
                        bss[prop] = int(bss[prop].microseconds) / 1000

                # Append BSS data to general object
                iface_data = {**iface_data, **bss}
            except Exception as e:
                logger.warning("Obtaining BSS data failed: {}".format(e))
                pass

        # Append data to global structure
        self.iface_data[if_index] = iface_data
        return NL_SKIP
Exemple #19
0
def test_no_security():
    """iw output to test against.

    BSS 00:0d:67:23:b8:46(on wlan0)
    TSF: 1680943821184 usec (19d, 10:55:43)
    freq: 2412
    beacon interval: 100 TUs
    capability: ESS ShortPreamble ShortSlotTime (0x0421)
    signal: -66.00 dBm
    last seen: 4630 ms ago
    Information elements from Probe Response frame:
    SSID: CableWiFi
    Supported rates: 2.0* 5.5* 11.0* 6.0 9.0 12.0 18.0 24.0
    DS Parameter set: channel 1
    TIM: DTIM Count 0 DTIM Period 1 Bitmap Control 0x0 Bitmap[0] 0x0
    Country: US    Environment: Outdoor only
        Channels [1 - 11] @ 36 dBm
    ERP: <no flags>
    Extended supported rates: 36.0 48.0 54.0
    HT capabilities:
        Capabilities: 0x2d
            RX LDPC
            HT20
            SM Power Save disabled
            RX HT20 SGI
            No RX STBC
            Max AMSDU length: 3839 bytes
            No DSSS/CCK HT40
        Maximum RX AMPDU length 65535 bytes (exponent: 0x003)
        Minimum RX AMPDU time spacing: No restriction (0x00)
        HT RX MCS rate indexes supported: 0-23
        HT TX MCS rate indexes are undefined
    HT operation:
         * primary channel: 1
         * secondary channel offset: no secondary
         * STA channel width: 20 MHz
         * RIFS: 0
         * HT protection: nonmember
         * non-GF present: 0
         * OBSS non-GF present: 0
         * dual beacon: 0
         * dual CTS protection: 0
         * STBC beacon: 0
         * L-SIG TXOP Prot: 0
         * PCO active: 0
         * PCO phase: 0
    Overlapping BSS scan params:
         * passive dwell: 20 TUs
         * active dwell: 10 TUs
         * channel width trigger scan interval: 300 s
         * scan passive total per channel: 200 TUs
         * scan active total per channel: 20 TUs
         * BSS width channel transition delay factor: 5
         * OBSS Scan Activity Threshold: 0.25 %
    Extended capabilities: HT Information Exchange Supported, SSID List
    WMM:     * Parameter version 1
         * BE: CW 15-1023, AIFSN 3
         * BK: CW 15-1023, AIFSN 7
         * VI: CW 7-15, AIFSN 2, TXOP 3008 usec
         * VO: CW 3-7, AIFSN 2, TXOP 1504 usec
    """
    data = bytearray(base64.b64decode(
        b'IgEAAAgALgCJnxAACAADAAgAAAAMAJkAAQAAAAMAAACgAS8ACgABAAANZyO4RgAADAADAIAxD2CHAQAAowAGAAAJQ2FibGVXaUZpAQiEi5YME'
        b'hgkMAMBAQUEAAEAAAcGVVNPAQskKgEAMgNIYGwtGi0AA////wAAAAAAAAAAAAAAAAAABAbm5w0APRYBAAEAAAAAAAAAAAAAAAAAAAAAAAAASg'
        b'4UAAoALAHIABQABQAZAH8GAQAAAgAA3RgAUPICAQEHAAOkAAAnpAAAQkNeAGIyLwDdCQADfwEBAAD/fwAMAA0AgDEPYIcBAACjAAsAAAlDYWJ'
        b'sZVdpRmkBCISLlgwSGCQwAwEBBQQAAQAABwZVU08BCyQqAQAyA0hgbC0aLQAD////AAAAAAAAAAAAAAAAAAAEBubnDQA9FgEAAQAAAAAAAAAA'
        b'AAAAAAAAAAAAAABKDhQACgAsAcgAFAAFABkAfwYBAAACAADdGABQ8gIBAQcAA6QAACekAABCQ14AYjIvAN0JAAN/AQEAAP9/AAYABABkAAAAB'
        b'gAFACEEAAAIAAIAbAkAAAgADAAAAAAACAAKAGwgAAAIAAcAOOb//w=='
    ))
    gnlh = genlmsghdr(data)
    tb = dict((i, None) for i in range(NL80211_ATTR_MAX + 1))
    nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), None)
    bss = dict()
    nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)
    bss_parsed = parse_bss(bss)
    assert '00:0d:67:23:b8:46' == bss_parsed['bssid']
    assert timedelta(microseconds=1680943821184) == bss_parsed['tsf']
    assert 2412 == bss_parsed['frequency']
    assert 100 == bss_parsed['beacon_interval']
    assert ['ESS', 'ShortPreamble', 'ShortSlotTime'] == sorted(bss_parsed['capability'])
    assert -66.0 == bss_parsed['signal']
    assert timedelta(milliseconds=4630) < bss_parsed['seen_ms_ago'] < timedelta(milliseconds=9999)
    assert u'CableWiFi' == bss_parsed['ssid']
    assert ['11.0*', '12.0', '18.0', '2.0*', '24.0', '5.5*', '6.0', '9.0'] == sorted(bss_parsed['supported_rates'])
    assert 1 == bss_parsed['channel']
    assert ['36.0', '48.0', '54.0'] == sorted(bss_parsed['extended_supported_rates'])
    assert 20 == bss_parsed['channel_width']
Exemple #20
0
def info_callback(msg, _):

    nlh = nlmsg_hdr(msg)
    gnlh = genlmsghdr(nlmsg_data(nlh))
    tb = dict((i, None) for i in range(NCSI_ATTR_MAX + 1))

    ret = genlmsg_parse(nlh, 0, tb, NCSI_ATTR_MAX, ncsi_policy)
    if ret != 0:
        reason = errmsg[abs(ret)]
        print("genlmsg_parse returned {}, {}".format(ret, reason))
        return ret

    if not NCSI_ATTR_PACKAGE_LIST in tb:
        print('No packages!')
        return -1

    rem = c_int()
    for nla in nla_for_each_nested(tb[NCSI_ATTR_PACKAGE_LIST], rem):
        ptb = dict()
        ret = nla_parse_nested(ptb, NCSI_PKG_ATTR_MAX, nla,
                               ncsi_package_policy)
        if ret < 0:
            print('Failed to parse package nest')
            return ret
        if NCSI_PKG_ATTR_ID in ptb:
            print('package {}'.format(nla_get_u32(ptb[NCSI_PKG_ATTR_ID])))
        else:
            print('package (with no id?)')
        if NCSI_PKG_ATTR_FORCED in ptb:
            print('this package is forced')
        print('----------')

        crem = c_int()
        for cnla in nla_for_each_nested(ptb[NCSI_PKG_ATTR_CHANNEL_LIST], crem):
            ctb = dict()
            ret = nla_parse_nested(ctb, NCSI_CHANNEL_ATTR_MAX, cnla,
                                   ncsi_channel_policy)
            if ret < 0:
                print('Failed to parse channel nest')
                return ret
            if NCSI_CHANNEL_ATTR_ID in ctb:
                channel = nla_get_u32(ctb[NCSI_CHANNEL_ATTR_ID])
                if NCSI_CHANNEL_ATTR_ACTIVE in ctb:
                    print('channel {} - active!'.format(channel))
                else:
                    print('channel {}'.format(channel))
                if NCSI_CHANNEL_ATTR_FORCED in ctb:
                    print('\tthis channel is forced')
            else:
                print('channel (with no id?)')
            if NCSI_CHANNEL_ATTR_VERSION_MAJOR in ctb:
                print('\tmajor version {}'.format(
                    nla_get_u32(ctb[NCSI_CHANNEL_ATTR_VERSION_MAJOR])))
            if NCSI_CHANNEL_ATTR_VERSION_MINOR in ctb:
                print('\tminor version {}'.format(
                    nla_get_u32(ctb[NCSI_CHANNEL_ATTR_VERSION_MINOR])))
            if NCSI_CHANNEL_ATTR_VERSION_STR in ctb:
                print('\tversion string {}'.format(
                    nla_get_string(ctb[NCSI_CHANNEL_ATTR_VERSION_STR])))
            if NCSI_CHANNEL_ATTR_LINK_STATE in ctb:
                print('\tlink state {}'.format(
                    nla_get_u32(ctb[NCSI_CHANNEL_ATTR_LINK_STATE])))
            if NCSI_CHANNEL_ATTR_VLAN_LIST in ctb:
                print('\tactive vlan ids:')
                rrem = c_int()
                vids = ctb[NCSI_CHANNEL_ATTR_VLAN_LIST]
                vid = nlattr(nla_data(vids))
                rrem.value = nla_len(vids)
                while nla_ok(vid, rrem):
                    print('\t\t{}'.format(nla_get_u16(vid)))
                    vid = nla_next(vid, rrem)

    return NL_SKIP
Exemple #21
0
def getStationInfo_callback(msg, results):
    # Dictionnary later populated with response message sub-attributes
    sinfo = dict()
    # Get the header of the message
    gnlh = genlmsghdr(nlmsg_data(nlmsg_hdr(msg)))
    tb = dict((i, None) for i in range(nl80211.NL80211_ATTR_MAX + 1))
    # Define the data structure of the netlink attributes we will receive
    stats_policy = dict(
        (i, None) for i in range(nl80211.NL80211_STA_INFO_MAX + 1))
    stats_policy.update({
        nl80211.NL80211_STA_INFO_INACTIVE_TIME:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_RX_BYTES:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_TX_BYTES:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_RX_PACKETS:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_TX_PACKETS:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_SIGNAL:
        nla_policy(type_=NLA_U8),
        nl80211.NL80211_STA_INFO_SIGNAL_AVG:
        nla_policy(type_=NLA_U8),
        nl80211.NL80211_STA_INFO_T_OFFSET:
        nla_policy(type_=NLA_U64),
        nl80211.NL80211_STA_INFO_TX_BITRATE:
        nla_policy(type_=NLA_NESTED),
        nl80211.NL80211_STA_INFO_RX_BITRATE:
        nla_policy(type_=NLA_NESTED),
        nl80211.NL80211_STA_INFO_LLID:
        nla_policy(type_=NLA_U16),
        nl80211.NL80211_STA_INFO_PLID:
        nla_policy(type_=NLA_U16),
        nl80211.NL80211_STA_INFO_PLINK_STATE:
        nla_policy(type_=NLA_U8),
        nl80211.NL80211_STA_INFO_TX_RETRIES:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_TX_FAILED:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_LOCAL_PM:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_PEER_PM:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_NONPEER_PM:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_CHAIN_SIGNAL:
        nla_policy(type_=NLA_NESTED),
        nl80211.NL80211_STA_INFO_RX_BYTES64:
        nla_policy(type_=NLA_U64),
        nl80211.NL80211_STA_INFO_TX_BYTES64:
        nla_policy(type_=NLA_U64),
        nl80211.NL80211_STA_INFO_BEACON_LOSS:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_CONNECTED_TIME:
        nla_policy(type_=NLA_U32),
        nl80211.NL80211_STA_INFO_BSS_PARAM:
        nla_policy(type_=NLA_NESTED),
    })
    # If any value in the stats_policy is empty, pad it with a default NLA_U8 type to avoid
    # any issue during validation
    for key in stats_policy:
        if stats_policy[key] is None:
            stats_policy[key] = nla_policy(type_=NLA_U8)
    # Parse the stream of attributes received into indexed chunks of data
    nla_parse(tb, nl80211.NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
              genlmsg_attrlen(gnlh, 0), None)
    # If we haven't received Station info data, don't go further and skip this message
    if tb[nl80211.NL80211_ATTR_STA_INFO] is None:
        return libnl.handlers.NL_SKIP
    # Finally, feed the attributes of the message into the chunk defined before
    nla_parse_nested(sinfo, nl80211.NL80211_STA_INFO_MAX,
                     tb[nl80211.NL80211_ATTR_STA_INFO], stats_policy)
    # Create the Station object
    station = Station()
    # Finally, if an attribute of interest is present, save it in the object
    if tb[nl80211.NL80211_ATTR_MAC]:
        # Convert the station MAC address to something human readable
        raw_mac = nla_get_string(tb[nl80211.NL80211_ATTR_MAC])
        if len(raw_mac) == 6:
            station.mac_addr = "%x:%x:%x:%x:%x:%x" % struct.unpack(
                "BBBBBB", raw_mac)
    if sinfo[nl80211.NL80211_STA_INFO_RX_BYTES]:
        station.rx_bytes = nla_get_u32(
            sinfo[nl80211.NL80211_STA_INFO_RX_BYTES])
    if sinfo[nl80211.NL80211_STA_INFO_TX_BYTES]:
        station.tx_bytes = nla_get_u32(
            sinfo[nl80211.NL80211_STA_INFO_TX_BYTES])
    if sinfo[nl80211.NL80211_STA_INFO_RX_PACKETS]:
        station.rx_packets = nla_get_u32(
            sinfo[nl80211.NL80211_STA_INFO_RX_PACKETS])
    if sinfo[nl80211.NL80211_STA_INFO_TX_PACKETS]:
        station.tx_packets = nla_get_u32(
            sinfo[nl80211.NL80211_STA_INFO_TX_PACKETS])
    if sinfo[nl80211.NL80211_STA_INFO_TX_FAILED]:
        station.tx_failed = nla_get_u32(
            sinfo[nl80211.NL80211_STA_INFO_TX_FAILED])
    if sinfo[nl80211.NL80211_STA_INFO_SIGNAL]:
        # Signal level is saved as an 8-bit byte, so we convert it to a signed integer
        raw_signal = nla_get_u8(sinfo[nl80211.NL80211_STA_INFO_SIGNAL])
        if raw_signal > 127:
            station.signal = raw_signal - 256
        else:
            station.signal = raw_signal
    # Append the station to the list of station and iterate to the next result
    results.append(station)
    return libnl.handlers.NL_SKIP