def dump_attrs(ofd, attrs, attrlen, prefix=0): """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/msg.c#L869. Positional arguments: ofd -- function to call with arguments similar to `logging.debug`. attrs -- nlattr class instance. attrlen -- length of payload (integer). Keyword arguments: prefix -- additional number of whitespace pairs to prefix each log statement with. """ prefix_whitespaces = ' ' * prefix rem = c_int() for nla in nla_for_each_attr(attrs, attrlen, rem): alen = nla_len(nla) if nla.nla_type == 0: ofd('%s [ATTR PADDING] %d octets', prefix_whitespaces, alen) else: is_nested = ' NESTED' if nla_is_nested(nla) else '' ofd('%s [ATTR %02d%s] %d octets', prefix_whitespaces, nla.nla_type, is_nested, alen) if nla_is_nested(nla): dump_attrs(ofd, nla_data(nla), alen, prefix + 1) else: dump_attr(ofd, nla, prefix) padlen = nla_padlen(alen) if padlen > 0: ofd('%s [PADDING] %d octets', prefix_whitespaces, padlen) dump_hex(ofd, bytearray_ptr(nla_data(nla), alen), padlen, prefix) if rem.value: ofd('%s [LEFTOVER] %d octets', prefix_whitespaces, rem)
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 dump_attr(ofd, attr, prefix=0): """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/msg.c#L862. Positional arguments: ofd -- function to call with arguments similar to `logging.debug`. attr -- nlattr class instance. Keyword arguments: prefix -- additional number of whitespace pairs to prefix each log statement with. """ dump_hex(ofd, nla_data(attr), nla_len(attr), prefix)
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
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