def print_genl_msg(_, ofd, hdr, ops, payloadlen): """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/msg.c#L831. Positional arguments: _ -- unused. ofd -- function to call with arguments similar to `logging.debug`. hdr -- Netlink message header (nlmsghdr class instance). ops -- cache operations (nl_cache_ops class instance). payloadlen -- length of payload in message (ctypes.c_int instance). Returns: data (bytearray_ptr). """ data = nlmsg_data(hdr) if payloadlen.value < GENL_HDRLEN: return data print_genl_hdr(ofd, data) payloadlen.value -= GENL_HDRLEN data = bytearray_ptr(data, GENL_HDRLEN) if ops: hdrsize = ops.co_hdrsize - GENL_HDRLEN if hdrsize > 0: if payloadlen.value < hdrsize: return data ofd(' [HEADER] %d octets', hdrsize) dump_hex(ofd, data, hdrsize, 0) payloadlen.value -= hdrsize data = bytearray_ptr(data, hdrsize) return data
def nla_put(msg, attrtype, datalen, data): """Add a unspecific attribute to Netlink message. https://github.com/thom311/libnl/blob/libnl3_2_25/lib/attr.c#L497 Reserves room for an unspecific attribute and copies the provided data into the message as payload of the attribute. Returns an error if there is insufficient space for the attribute. Positional arguments: msg -- Netlink message (nl_msg class instance). attrtype -- attribute type (integer). datalen -- length of data to be used as payload (integer). data -- data to be used as attribute payload (bytearray). Returns: 0 on success or a negative error code. """ nla = nla_reserve(msg, attrtype, datalen) if not nla: return -NLE_NOMEM if datalen <= 0: return 0 nla_data(nla)[:datalen] = data[:datalen] _LOGGER.debug('msg 0x%x: attr <0x%x> %d: Wrote %d bytes at offset +%d', id(msg), id(nla), nla.nla_type, datalen, nla.bytearray.slice.start - nlmsg_data(msg.nm_nlh).slice.start) return 0
def nla_put(msg, attrtype, datalen, data): """Add a unspecific attribute to Netlink message. https://github.com/thom311/libnl/blob/libnl3_2_25/lib/attr.c#L497 Reserves room for an unspecific attribute and copies the provided data into the message as payload of the attribute. Returns an error if there is insufficient space for the attribute. Positional arguments: msg -- Netlink message (nl_msg class instance). attrtype -- attribute type (integer). datalen -- length of data to be used as payload (integer). data -- data to be used as attribute payload (bytearray). Returns: 0 on success or a negative error code. """ nla = nla_reserve(msg, attrtype, datalen) if not nla: return -NLE_NOMEM if datalen <= 0: return 0 nla_data(nla)[:datalen] = data[:datalen] _LOGGER.debug( 'msg 0x%x: attr <0x%x> %d: Wrote %d bytes at offset +%d', id(msg), id(nla), nla.nla_type, datalen, nla.bytearray.slice.start - nlmsg_data(msg.nm_nlh).slice.start) return 0
def nlmsg_attrdata(nlh, hdrlen): """Head of attributes data. https://github.com/thom311/libnl/blob/libnl3_2_25/lib/msg.c#L143 Positional arguments: nlh -- Netlink message header (nlmsghdr class instance). hdrlen -- length of family specific header (integer). Returns: First attribute (nlattr class instance with others in its payload). """ data = nlmsg_data(nlh) return libnl.linux_private.netlink.nlattr(bytearray_ptr(data, libnl.linux_private.netlink.NLMSG_ALIGN(hdrlen)))
def nla_put_nested(msg, attrtype, nested): """Add nested attributes to Netlink message. https://github.com/thom311/libnl/blob/libnl3_2_25/lib/attr.c#L772 Takes the attributes found in the `nested` message and appends them to the message `msg` nested in a container of the type `attrtype`. The `nested` message may not have a family specific header. Positional arguments: msg -- Netlink message (nl_msg class instance). attrtype -- attribute type (integer). nested -- message containing attributes to be nested (nl_msg class instance). Returns: 0 on success or a negative error code. """ _LOGGER.debug('msg 0x%x: attr <> %d: adding msg 0x%x as nested attribute', id(msg), attrtype, id(nested)) return nla_put(msg, attrtype, nlmsg_datalen(nested.nm_nlh), nlmsg_data(nested.nm_nlh))
def dump_error_msg(msg, ofd=_LOGGER.debug): """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/msg.c#L908. Positional arguments: msg -- message to print (nl_msg class instance). Keyword arguments: ofd -- function to call with arguments similar to `logging.debug`. """ hdr = nlmsg_hdr(msg) err = libnl.linux_private.netlink.nlmsgerr(nlmsg_data(hdr)) ofd(' [ERRORMSG] %d octets', err.SIZEOF) if nlmsg_len(hdr) >= err.SIZEOF: ofd(' .error = %d "%s"', err.error, os.strerror(-err.error)) ofd(' [ORIGINAL MESSAGE] %d octets', hdr.SIZEOF) errmsg = nlmsg_inherit(err.msg) print_hdr(ofd, errmsg)
def nla_reserve(msg, attrtype, attrlen): """Reserve space for an attribute. https://github.com/thom311/libnl/blob/libnl3_2_25/lib/attr.c#L456 Reserves room for an attribute in the specified Netlink message and fills in the attribute header (type, length). Returns None if there is insufficient space for the attribute. Any padding between payload and the start of the next attribute is zeroed out. Positional arguments: msg -- Netlink message (nl_msg class instance). attrtype -- attribute type (integer). attrlen -- length of payload (integer). Returns: nlattr class instance allocated to the new space or None on failure. """ tlen = NLMSG_ALIGN(msg.nm_nlh.nlmsg_len) + nla_total_size(attrlen) if tlen > msg.nm_size: return None nla = nlattr(nlmsg_tail(msg.nm_nlh)) nla.nla_type = attrtype nla.nla_len = nla_attr_size(attrlen) if attrlen: padlen = nla_padlen(attrlen) nla.bytearray[nla.nla_len:nla.nla_len + padlen] = bytearray(b'\0') * padlen msg.nm_nlh.nlmsg_len = tlen _LOGGER.debug( 'msg 0x%x: attr <0x%x> %d: Reserved %d (%d) bytes at offset +%d nlmsg_len=%d', id(msg), id(nla), nla.nla_type, nla_total_size(attrlen), attrlen, nla.bytearray.slice.start - nlmsg_data(msg.nm_nlh).slice.start, msg.nm_nlh.nlmsg_len) return nla
def nla_reserve(msg, attrtype, attrlen): """Reserve space for an attribute. https://github.com/thom311/libnl/blob/libnl3_2_25/lib/attr.c#L456 Reserves room for an attribute in the specified Netlink message and fills in the attribute header (type, length). Returns None if there is insufficient space for the attribute. Any padding between payload and the start of the next attribute is zeroed out. Positional arguments: msg -- Netlink message (nl_msg class instance). attrtype -- attribute type (integer). attrlen -- length of payload (integer). Returns: nlattr class instance allocated to the new space or None on failure. """ tlen = NLMSG_ALIGN(msg.nm_nlh.nlmsg_len) + nla_total_size(attrlen) if tlen > msg.nm_size: return None nla = nlattr(nlmsg_tail(msg.nm_nlh)) nla.nla_type = attrtype nla.nla_len = nla_attr_size(attrlen) if attrlen: padlen = nla_padlen(attrlen) nla.bytearray[nla.nla_len:nla.nla_len + padlen] = bytearray(b'\0') * padlen msg.nm_nlh.nlmsg_len = tlen _LOGGER.debug('msg 0x%x: attr <0x%x> %d: Reserved %d (%d) bytes at offset +%d nlmsg_len=%d', id(msg), id(nla), nla.nla_type, nla_total_size(attrlen), attrlen, nla.bytearray.slice.start - nlmsg_data(msg.nm_nlh).slice.start, msg.nm_nlh.nlmsg_len) return nla
def print_msg(msg, ofd, hdr): """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/msg.c#L929. Positional arguments: msg -- Netlink message (nl_msg class instance). ofd -- function to call with arguments similar to `logging.debug`. hdr -- Netlink message header (nlmsghdr class instance). """ payloadlen = c_int(nlmsg_len(hdr)) attrlen = 0 data = nlmsg_data(hdr) ops = nl_cache_ops_associate_safe(msg.nm_protocol, hdr.nlmsg_type) if ops: attrlen = nlmsg_attrlen(hdr, ops.co_hdrsize) payloadlen.value -= attrlen if msg.nm_protocol == libnl.linux_private.netlink.NETLINK_GENERIC: data = print_genl_msg(msg, ofd, hdr, ops, payloadlen) if payloadlen.value: ofd(' [PAYLOAD] %d octets', payloadlen.value) dump_hex(ofd, data, payloadlen.value, 0) if attrlen: attrs = nlmsg_attrdata(hdr, ops.co_hdrsize) attrlen = nlmsg_attrlen(hdr, ops.co_hdrsize) dump_attrs(ofd, attrs, attrlen, 0)