Enough serialization to generate a query that gets a working response.

This commit is contained in:
Ian Gulliver
2015-01-07 06:27:01 +00:00
parent fc3bf6d59a
commit 485ad84b64

View File

@@ -1,17 +1,13 @@
#!/usr/bin/python2.7 #!/usr/bin/python2.7
import collections import collections
import os
import random
import socket import socket
import struct import struct
sock = socket.socket(socket.AF_NETLINK, socket.SOCK_DGRAM, 16)
sock.bind((0,0))
query = '\34\0\0\0\24\0\5\3\\7\252T\367\16\0\0\21\0\0\0\10\0\3\0\6\0\0\0'
sock.send(query)
data = sock.recv(1024)
class Iterator(object):
class ParsedData(object):
def __init__(self, data): def __init__(self, data):
self.data = data self.data = data
self.offset = 0 self.offset = 0
@@ -21,104 +17,142 @@ class ParsedData(object):
return '(%d bytes): %r' % (len(data), data) return '(%d bytes): %r' % (len(data), data)
def Advance(self, offset_incr): def Advance(self, offset_incr):
assert self.offset + offset_incr <= len(self.data)
self.offset += offset_incr self.offset += offset_incr
def Extract(self, length):
assert self.offset + length <= len(self.data)
ret = self.data[self.offset:self.offset + length]
self.Advance(length)
return ret
def AtEnd(self): def AtEnd(self):
return self.offset == len(self.data) return self.offset == len(self.data)
class Parser(struct.Struct): class Accumulator(object):
def __init__(self, format, fields=None): def __init__(self):
super(Parser, self).__init__(format) self._parts = []
self._fields = fields
def Parse(self, parsed_data, targetlen=None): def __str__(self):
return ''.join(self._parts)
def __len__(self):
return sum(len(part) for part in self._parts)
def Append(self, value):
self._parts.append(value)
class SingleStructParser(struct.Struct):
def Unpack(self, iterator, targetlen=None):
if targetlen is not None: if targetlen is not None:
assert self.size == targetlen, 'Actual bytes: %d, expected bytes: %d' % (targetlen, self.size) assert self.size == targetlen, 'Actual bytes: %d, expected bytes: %d' % (targetlen, self.size)
values = self.unpack_from(parsed_data.data, parsed_data.offset) values = self.unpack_from(iterator.data, iterator.offset)
parsed_data.Advance(self.size) iterator.Advance(self.size)
if self._fields:
return collections.OrderedDict(zip(self._fields, values))
else:
assert len(values) == 1 assert len(values) == 1
return values[0] return values[0]
def Pack(self, accumulator, value):
accumulator.Append(self.pack(value))
class StructParser(struct.Struct):
def __init__(self, format, fields=None):
super(StructParser, self).__init__(format)
self._fields = fields
def Unpack(self, iterator, targetlen=None):
if targetlen is not None:
assert self.size == targetlen, 'Actual bytes: %d, expected bytes: %d' % (targetlen, self.size)
values = self.unpack_from(iterator.data, iterator.offset)
iterator.Advance(self.size)
return collections.OrderedDict(zip(self._fields, values))
def Pack(self, accumulator, **values):
ordered_values = []
for field in self._fields:
ordered_values.append(values[field])
accumulator.Append(self.pack(*ordered_values))
class StringParser(object): class StringParser(object):
def Parse(self, parsed_data, targetlen): def Unpack(self, iterator, targetlen):
ret = parsed_data.data[parsed_data.offset:parsed_data.offset + targetlen] return iterator.Extract(targetlen)
parsed_data.Advance(targetlen)
return ret def Pack(self, accumulator, value):
accumulator.Append(value)
class EmptyParser(object): class EmptyParser(object):
def Parse(self, parsed_data, targetlen=None): def Unpack(self, iterator, targetlen=None):
assert not targetlen assert not targetlen
return True return True
def Pack(self, accumulator, value=None):
pass
nlmsghdr = Parser('LHHLL', ('length', 'type', 'flags', 'seq', 'pid'))
genlmsghdr = Parser('BBH', ('cmd', 'version', 'reserved')) nlmsghdr = StructParser('LHHLL', ('length', 'type', 'flags', 'seq', 'pid'))
genlmsghdr = StructParser('BBH', ('cmd', 'version', 'reserved'))
class Attribute(object): class Attribute(object):
_nlattr = Parser('HH', ('len', 'type')) _nlattr = StructParser('HH', ('len', 'type'))
def __init__(self, attributes): def __init__(self, attributes):
super(Attribute, self).__init__() super(Attribute, self).__init__()
self._attributes = attributes self._attributes = attributes
def Parse(self, parsed_data, targetlen=None): def Unpack(self, iterator, targetlen=None):
nlattr = self._nlattr.Parse(parsed_data) nlattr = self._nlattr.Unpack(iterator)
if targetlen is not None: if targetlen is not None:
assert nlattr['len'] == targetlen assert nlattr['len'] == targetlen
name, sub_parser = self._attributes.get(nlattr['type'], (None, None)) name, sub_parser = self._attributes.get(nlattr['type'], (None, None))
assert sub_parser, 'Unknown attribute type %d, len %d' % (nlattr['type'], nlattr['len']) assert sub_parser, 'Unknown attribute type %d, len %d' % (nlattr['type'], nlattr['len'])
sub_len = nlattr['len'] - self._nlattr.size sub_len = nlattr['len'] - self._nlattr.size
ret = { ret = {
name: sub_parser.Parse(parsed_data, sub_len) name: sub_parser.Unpack(iterator, sub_len)
} }
padding = ((nlattr['len'] + 4 - 1) & ~3) - nlattr['len'] padding = ((nlattr['len'] + 4 - 1) & ~3) - nlattr['len']
parsed_data.Advance(padding) iterator.Advance(padding)
return ret return ret
def Pack(self, accumulator, attrtype, **attrargs):
sub_parser = self._attributes[attrtype][1]
sub_accumulator = Accumulator()
sub_parser.Pack(sub_accumulator, **attrargs)
self._nlattr.Pack(accumulator, len=self._nlattr.size + len(sub_accumulator), type=attrtype)
accumulator.Append(str(sub_accumulator))
class Attributes(object): class Attributes(object):
def __init__(self, attributes): def __init__(self, attributes):
super(Attributes, self).__init__() super(Attributes, self).__init__()
self._attribute = Attribute(attributes) self._attribute = Attribute(attributes)
def Parse(self, parsed_data, targetlen=None): def Unpack(self, iterator, targetlen=None):
if targetlen is None: if targetlen is not None:
local_parsed_data = parsed_data iterator = Iterator(iterator.Extract(targetlen))
else:
local_parsed_data = ParsedData(parsed_data.data[parsed_data.offset:parsed_data.offset + targetlen])
parsed_data.Advance(targetlen)
ret = collections.OrderedDict() ret = collections.OrderedDict()
while not local_parsed_data.AtEnd(): while not iterator.AtEnd():
ret.update(self._attribute.Parse(local_parsed_data)) ret.update(self._attribute.Unpack(iterator))
return ret return ret
def Pack(self, accumulator, attrtype, **attrargs):
return self._attribute.Pack(accumulator, attrtype, **attrargs)
flag = EmptyParser() flag = EmptyParser()
string = StringParser() string = StringParser()
u8 = Parser('B') u8 = SingleStructParser('B')
u16 = Parser('H') u16 = SingleStructParser('H')
u32 = Parser('L') u32 = SingleStructParser('L')
u64 = Parser('Q') u64 = SingleStructParser('Q')
sta_flag_authorized = 1 << 0
sta_flag_short_preamble = 1 << 1
sta_flag_wme = 1 << 2
sta_flag_mfp = 1 << 3
sta_flag_authenticated = 1 << 4
sta_flag_tdls_peer = 1 << 5
sta_flag_associated = 1 << 6
rate_info = Attributes({ rate_info = Attributes({
1: ('bitrate', u16), 1: ('bitrate', u16),
2: ('mcs', u8), 2: ('mcs', u8),
@@ -149,7 +183,7 @@ sta_info = Attributes({
14: ('rx_bitrate', rate_info), 14: ('rx_bitrate', rate_info),
15: ('bss_param', bss_param), 15: ('bss_param', bss_param),
16: ('connected_time', u32), 16: ('connected_time', u32),
17: ('sta_flags', Parser('LL', ('mask', 'values'))), 17: ('sta_flags', StructParser('LL', ('mask', 'values'))),
18: ('beacon_loss', u32), 18: ('beacon_loss', u32),
23: ('rx_bytes_64', u64), 23: ('rx_bytes_64', u64),
24: ('tx_bytes_64', u64), 24: ('tx_bytes_64', u64),
@@ -162,7 +196,54 @@ nl80211_attr = Attributes({
46: ('generation', u32), 46: ('generation', u32),
}) })
parsed_data = ParsedData(data) F_REQUEST = 1 << 0
print 'nlmsghdr: %s' % nlmsghdr.Parse(parsed_data) F_MULTI = 1 << 1
print 'genlmsghdr: %s' % genlmsghdr.Parse(parsed_data) F_ACK = 1 << 2
print 'nl80211_attr: %s' % nl80211_attr.Parse(parsed_data) F_ECHO = 1 << 3
F_DUMP_INTR = 1 << 4
F_ROOT = 1 << 8
F_MATCH = 1 << 9
F_ATOMIC = 1 << 10
F_DUMP = F_ROOT | F_MATCH
CMD_GET_STATION = 17
STA_FLAG_AUTHORIZED = 1 << 0
STA_FLAG_SHORT_PREAMBLE = 1 << 1
STA_FLAG_WME = 1 << 2
STA_FLAG_MFP = 1 << 3
STA_FLAG_AUTHENTICATED = 1 << 4
STA_FLAG_TDLS_PEER = 1 << 5
STA_FLAG_ASSOCIATED = 1 << 6
ATTR_IFINDEX = 3
genquery = Accumulator()
nlmsghdr.Pack(
genquery,
length=28, # XXX
type=20, # XXX
flags=F_REQUEST | F_ACK | F_DUMP,
seq=random.randint(0, 2 ** 32 - 1),
pid=os.getpid())
genlmsghdr.Pack(
genquery,
cmd=CMD_GET_STATION,
version=0,
reserved=0)
nl80211_attr.Pack(
genquery,
attrtype=ATTR_IFINDEX,
value=6)
sock = socket.socket(socket.AF_NETLINK, socket.SOCK_DGRAM, 16)
sock.bind((0,0))
sock.send(str(genquery))
data = sock.recv(4096)
iterator = Iterator(data)
print 'nlmsghdr: %s' % nlmsghdr.Unpack(iterator)
print 'genlmsghdr: %s' % genlmsghdr.Unpack(iterator)
print 'nl80211_attr: %s' % nl80211_attr.Unpack(iterator)