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
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 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
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