def test_lookup_genl_family(self, socket_mock): sock = socket_mock.return_value msg = get_genl_message( nla_u16(CTRL_ATTR_FAMILY_ID, 123) + nla(CTRL_ATTR_MCAST_GROUPS, nla(1, nla_str(CTRL_ATTR_MCAST_GRP_NAME, "foo") + nla_u32(CTRL_ATTR_MCAST_GRP_ID, 1)) + nla(2, nla_str(CTRL_ATTR_MCAST_GRP_NAME, "bar") + nla_u32(CTRL_ATTR_MCAST_GRP_ID, 2)))) sock.recv.side_effect = [msg] family = lookup_genl_family("dummy_family") [msg] = sock.get_sent_messages() assert_bufs_equal( msg, get_genl_message( mtype=GENL_ID_CTRL, flags=NLM_F_REQUEST, cmd=CTRL_CMD_GETFAMILY, version=GNL_FAMILY_VERSION, payload=nla_str(CTRL_ATTR_FAMILY_NAME, "dummy_family"))) self.assertEqual(family, GenlFamilyInfo(123, {"foo": 1, "bar": 2}))
def main(): parser = ArgumentParser(description=__doc__) parser.add_argument("command", help="Name of nl80211 command to call") parser.add_argument("params", help="JSON string with command params") args = parser.parse_args() family = lookup_genl_family("nl80211") sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, NETLINK_GENERIC) sock.bind((0, 0)) msg = get_genl_message(mtype=family.id, flags=NLM_F_REQUEST, cmd=nl80211_constants[args.command], payload=nl80211_schema.build(json.loads( args.params))) sock.send(msg) msg = sock.recv(8192) nl_header, nl_payload = parse_nl_message(msg) if nl_header.mtype == NLMSG_ERROR: raise RuntimeError("Error {} from command".format( parse_nl_error(nl_payload))) nl_header, genl_header, payload = parse_genl_message(msg) print( json.dumps(nl80211_schema.parse(payload), cls=MyJsonEncoder, indent=4))
def main(): # We need to look up the family ID which will go in the nl header's type # field. This also gives us the IDs we'd need to subscribe the socket to any # broadcast groups exposed by the family. family = lookup_genl_family("nl80211") sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, NETLINK_GENERIC) sock.bind((0, 0)) # We use get_genl_message to build a Generic Netlink message. The nl80211 # command goes in the cmd field of the genl header. # The payload is built using the canned nl0211 schema, using kwargs to # specify the attribute values used to express command params. # We could instead pass a dict, in which case we'd use the full attribute # names instead of shortened Pythonic names, e.g. instead of ifindex=foo # we could pass {"NL80211_ATTR_IFINDEX": foo}. msg = get_genl_message( mtype=family.id, flags=NLM_F_REQUEST, cmd=NL80211_CMD_GET_INTERFACE, payload=nl80211_schema.build(ifindex=if_nametoindex(argv[1]))) sock.send(msg) # Note the fixed size receive. This library lacks support for multi-part # messages. msg = sock.recv(8192) # Parse out the nl and genl header nl_header, genl_header, payload = parse_genl_message(msg) # Now we use the same canned schema to parse then attributes in the reply # payload info = nl80211_schema.parse(payload) # The attributes can be accessed like a dict; in this case the keys are the # full attribute names. For exmple if your WiFi is connected to a network , # these prints will include a line something like: # NL80211_ATTR_SSID = Darude-LANStorm print("Raw data:") for key in info: print(" {} = {}".format(key, info[key])) # Then for convenience we can also access the attributes as Python # attributes using nicer names. The nl80211 schema (see nl80211.py) doesn't # specify the names for the Python attributes, so we get the default # behaviour, which is that the Python names are determined by finding the # full name's unique suffix amongst its siblings and lower-casing it. # So instead of info["NL80211_ATTR_SSID"] we can just access info.ssid. print("\nname: '{}' | MAC: {} | Current SSID: '{}'".format( info.ifname, ":".join("{:02x}".format(b) for b in info.mac), info.ssid))
def do_nl80211_query(sock, cmd, **kwargs): """Call an nl80211 cmd (with **kwargs) and return the parsed response""" # We use get_genl_message to build a Generic Netlink message. The nl80211 # command goes in the cmd field of the genl header. # The payload is built using the canned nl0211 schema, using kwargs to # specify the attribute values used to express command params. msg = get_genl_message(mtype=nl80211_family.id, flags=NLM_F_REQUEST, cmd=cmd, payload=nl80211_schema.build(**kwargs)) sock.send(msg) msg = sock.recv(8192) nl_header, genl_header, payload = parse_genl_message(msg) return nl80211_schema.parse(payload)