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
Example #2
0
File: ctrl.py Project: 0x90/libnl
def parse_mcast_grps(family, grp_attr):
    """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/ctrl.c#L64.

    Positional arguments:
    family -- genl_family class instance.
    grp_attr -- nlattr class instance.

    Returns:
    0 on success or a negative error code.
    """
    remaining = c_int()
    if not grp_attr:
        raise BUG

    for nla in nla_for_each_nested(grp_attr, remaining):
        tb = dict()
        err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla, family_grp_policy)
        if err < 0:
            return err
        if not tb[CTRL_ATTR_MCAST_GRP_ID] or not tb[CTRL_ATTR_MCAST_GRP_NAME]:
            return -NLE_MISSING_ATTR

        id_ = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID])
        name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME])

        err = genl_family_add_grp(family, id_, name)
        if err < 0:
            return err

    return 0
Example #3
0
def parse_mcast_grps(family, grp_attr):
    """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/ctrl.c#L64.

    Positional arguments:
    family -- genl_family class instance.
    grp_attr -- nlattr class instance.

    Returns:
    0 on success or a negative error code.
    """
    remaining = c_int()
    if not grp_attr:
        raise BUG

    for nla in nla_for_each_nested(grp_attr, remaining):
        tb = dict()
        err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla,
                               family_grp_policy)
        if err < 0:
            return err
        if not tb[CTRL_ATTR_MCAST_GRP_ID] or not tb[CTRL_ATTR_MCAST_GRP_NAME]:
            return -NLE_MISSING_ATTR

        id_ = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID])
        name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME])

        err = genl_family_add_grp(family, id_, name)
        if err < 0:
            return err

    return 0
Example #4
0
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
    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
Example #6
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
Example #7
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