Esempio n. 1
0
def nla_parse(msg, l, mtype, stream, idx):
    """
     parses attributes in stream, putting them in msg
     :param msg: current message
     :param l: total length of message
     :param mtype: message content
     :param stream: byte stream
     :param idx: current index in stream
    """
    # get policy family NOTE: cheating here, we know it's either generic or nl80211
    pol = 'ctrl_attr' if mtype == nlh.NETLINK_GENERIC else 'nl80211_attr'
    attrlen = nlh.NLATTRHDRLEN  # pull out these to avoid
    attrhdr = nlh.nl_nlattrhdr  # doing so in each iteration

    # eat the stream until the end
    while idx < l:
        a = atype = alen = None  # shut pycharm up about unitialized variable
        try:
            alen, atype = struct.unpack_from(attrhdr, stream,
                                             idx)  # get length, type
            idx += attrlen  # move to attr start
            alen -= attrlen  # attr length (w/ padding)
            a = stream[idx:idx + alen]  # attr value
            dt = nla_datatype(pol, atype)  # attr datatype

            # Note: we use unpack_from which will ignore the null bytes in numeric
            # datatypes & for strings, strip trailing null bytes
            # dt == nlh.NLA_UNSPEC: ignore
            if _PY3_ and (dt == nlh.NLA_STRING or dt == nlh.NLA_UNSPEC):
                # python 3 returns a bytes object, convert to string
                try:
                    a = a.decode('ascii')
                except UnicodeDecodeError:
                    pass  # F**k You Python 3
            if dt == nlh.NLA_STRING: a = _nla_strip_(a)
            elif dt == nlh.NLA_U8: a = struct.unpack_from("B", a, 0)[0]
            elif dt == nlh.NLA_U16: a = struct.unpack_from("H", a, 0)[0]
            elif dt == nlh.NLA_U32: a = struct.unpack_from("I", a, 0)[0]
            elif dt == nlh.NLA_U64: a = struct.unpack_from("Q", a, 0)[0]
            elif dt == nlh.NLA_FLAG: a = ''  # flags should be 0 size
            elif dt == nlh.NLA_MSECS: a = struct.unpack_from("Q", a, 0)[0]
            elif dt == nlh.NLA_SET_U8: a = nla_parse_set(a, nlh.NLA_U8)
            elif dt == nlh.NLA_SET_U16: a = nla_parse_set(a, nlh.NLA_U16)
            elif dt == nlh.NLA_SET_U32: a = nla_parse_set(a, nlh.NLA_U32)
            elif dt == nlh.NLA_SET_U64: a = nla_parse_set(a, nlh.NLA_U64)
            elif dt == nlh.NLA_NESTED: a = nla_parse_nested(a)
            nla_put(msg, a, atype, dt)
        except struct.error:  # append as Error, stripping null bytes
            nla_put(msg, _nla_strip_(a), atype, nlh.NLA_ERROR)
        except error as e:
            if e.errno == errno.EINVAL:  # a nested or set failed to parse correctly
                nla_put(msg, _nla_strip_(a), atype, nlh.NLA_ERROR)
            else:
                raise
        except MemoryError as e:  # hopefully don't get here
            raise error(
                -1,
                "Attr type {0} of pol {1} failed: {2}".format(atype, pol, e))
        idx = nlh.NLMSG_ALIGN(idx + alen)  # move index to next attr
Esempio n. 2
0
def nla_parse_nested(nested):
    """
     :param nested: the nested attribute with attribute header removed
     :returns: list of tuples (index, data) where index is the index
      into an enum structure and attribute is the packed attribute)
      Callers must parse these themselves - see below for details

      From libnl (Thomas Graf)
      When nesting attributes, the nested attributes are included as payload of
      a container attribute. Attributes are nested by surrounding them with calls
      to nla_nest_start() and nla_nest_end().

       <-------- nla_attr_size(payload) --------->
       +------------------+-----+------------------+-----+
       | Attribute Header | Pad |     Payload      | Pad |
       +------------------+-----+------------------+-----+

      Nested attributes (after removing the Attribute header) should have the
      form:

       +--------+--------+-----+
       | Length |Payload | Pad |
       +--------+--------+-----+
       <-- 2 --><- var ->< var >

      where:
      Length (u16) is the length of the nested attribute (excluding padding
       affixed to the end to align the attribute). The size of padding is
       determined by NLMSG_ALIGN
      Payload has the format:

      +-------+--------+-----+
      | Index |  Data  | Pad |
      +-------+--------+-----+
      <-- 2 --><- var ->< var >

      where index is the index into an enum structure as determined by the
      attribute type of the nested attribute which is found in the Attribute
      Header
    """
    ns = []
    idx = 0
    l = len(nested)
    while idx < l:
        # first two bytes define length, including these bytes, length does not
        # include pad byte(s) affixed to end for proper alignment
        alen = struct.unpack_from("H", nested, idx)[0]
        if alen == 0:
            raise EnvironmentError(errno.EINVAL, "Invalid nesting")
        # ns.append(nested[idx+2:idx+alen]) # don't include the length bytes
        nattr = nested[idx + 2 : idx + alen]
        ns.append((struct.unpack_from("H", nattr, 0)[0], nattr[2:]))
        idx += nlh.NLMSG_ALIGN(alen)
    return ns