def test_repr(): """Test repr() of instances.""" assert 'c_byte(123)' == repr(c_byte(123)) if sys.maxsize > 2 ** 32: # 64-bit. assert 'c_int(1234567890)' == repr(c_int(1234567890)) else: assert 'c_long(1234567890)' == repr(c_int(1234567890)).replace('L)', ')') assert 'c_byte(123)' == repr(c_int8(123)) assert 'c_long(1234567890)' == repr(c_long(1234567890)).replace('L)', ')') if sys.maxsize > 2 ** 32: # 64-bit. assert 'c_long(1234567890123456789)' == repr(c_longlong(1234567890123456789)).replace('L)', ')') else: assert 'c_longlong(1234567890123456789)' == repr(c_longlong(1234567890123456789)).replace('L)', ')') assert 'c_ushort(12345)' == repr(c_uint16(12345)) if sys.maxsize > 2 ** 32: # 64-bit. assert 'c_uint(1234567890)' == repr(c_uint32(1234567890)).replace('L)', ')') else: assert 'c_ulong(1234567890)' == repr(c_uint32(1234567890)).replace('L)', ')') if sys.maxsize > 2 ** 32: # 64-bit. assert 'c_ulong(12345678901234567890)' == repr(c_uint64(12345678901234567890)).replace('L)', ')') else: assert 'c_ulonglong(12345678901234567890)' == repr(c_uint64(12345678901234567890)).replace('L)', ')') assert 'c_ubyte(123)' == repr(c_uint8(123)) assert 'c_ubyte(123)' == repr(c_ubyte(123)) if sys.maxsize > 2 ** 32: # 64-bit. assert 'c_uint(1234567890)' == repr(c_uint(1234567890)).replace('L)', ')') else: assert 'c_ulong(1234567890)' == repr(c_uint(1234567890)).replace('L)', ')') assert 'c_ulong(1234567890)' == repr(c_ulong(1234567890)).replace('L)', ')') if sys.maxsize > 2 ** 32: # 64-bit. assert 'c_ulong(12345678901234567890)' == repr(c_ulonglong(12345678901234567890)).replace('L)', ')') else: assert 'c_ulonglong(12345678901234567890)' == repr(c_ulonglong(12345678901234567890)).replace('L)', ')') assert 'c_ushort(12345)' == repr(c_ushort(12345))
def test_nla_put_get_u32(): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && ./a.out #include <netlink/msg.h> int main() { int rem, i, range[] = { 0, 1, 2, 19, 20, 50 }; struct nl_msg *msg = nlmsg_alloc(); struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *nla; for (i = 0; i < (sizeof(range) / sizeof(int)); i++) nla_put_u32(msg, i, range[i]); nlmsg_for_each_attr(nla, nlh, 0, rem) printf("type: %d; nla_get_u32: %d\n", nla_type(nla), nla_get_u32(nla)); nlmsg_free(msg); return 0; } // Expected output: // type: 0; nla_get_u32: 0 // type: 1; nla_get_u32: 1 // type: 2; nla_get_u32: 2 // type: 3; nla_get_u32: 19 // type: 4; nla_get_u32: 20 // type: 5; nla_get_u32: 50 """ rem = c_int() range_ = (0, 1, 2, 19, 20, 50) msg = nlmsg_alloc() nlh = nlmsg_hdr(msg) for i in range(len(range_)): libnl.attr.nla_put_u32(msg, i, range_[i]) i = 0 for nla in nlmsg_for_each_attr(nlh, 0, rem): assert i == libnl.attr.nla_type(nla) assert range_[i] == libnl.attr.nla_get_u32(nla) i += 1
def test_maximum(): """Test maximum valid integer value.""" assert 127 == c_byte.from_buffer(bytearray(c_byte(127))).value assert 2147483647 == c_int.from_buffer(bytearray(c_int(2147483647))).value assert 127 == c_int8.from_buffer(bytearray(c_int8(127))).value if sys.maxsize > 2**32: # 64-bit. assert 9223372036854775807 == c_long.from_buffer( bytearray(c_long(9223372036854775807))).value else: assert 2147483647 == c_long.from_buffer(bytearray( c_long(2147483647))).value assert 9223372036854775807 == c_longlong.from_buffer( bytearray(c_longlong(9223372036854775807))).value assert 65535 == c_uint16.from_buffer(bytearray(c_uint16(65535))).value assert 4294967295 == c_uint32.from_buffer(bytearray( c_uint32(4294967295))).value assert 18446744073709551615 == c_uint64.from_buffer( bytearray(c_uint64(18446744073709551615))).value assert 255 == c_uint8.from_buffer(bytearray(c_uint8(255))).value assert 255 == c_ubyte.from_buffer(bytearray(c_ubyte(255))).value assert 4294967295 == c_uint.from_buffer(bytearray( c_uint(4294967295))).value if sys.maxsize > 2**32: # 64-bit. assert 18446744073709551615 == c_ulong.from_buffer( bytearray(c_ulong(18446744073709551615))).value else: assert 4294967295 == c_ulong.from_buffer(bytearray( c_ulong(4294967295))).value assert 18446744073709551615 == c_ulonglong.from_buffer( bytearray(c_ulonglong(18446744073709551615))).value assert 65535 == c_ushort.from_buffer(bytearray(c_ushort(65535))).value
def dump_attrs(ofd, attrs, attrlen, prefix=0): """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/msg.c#L869. Positional arguments: ofd -- function to call with arguments similar to `logging.debug`. attrs -- nlattr class instance. attrlen -- length of payload (integer). Keyword arguments: prefix -- additional number of whitespace pairs to prefix each log statement with. """ prefix_whitespaces = ' ' * prefix rem = c_int() for nla in nla_for_each_attr(attrs, attrlen, rem): alen = nla_len(nla) if nla.nla_type == 0: ofd('%s [ATTR PADDING] %d octets', prefix_whitespaces, alen) else: is_nested = ' NESTED' if nla_is_nested(nla) else '' ofd('%s [ATTR %02d%s] %d octets', prefix_whitespaces, nla.nla_type, is_nested, alen) if nla_is_nested(nla): dump_attrs(ofd, nla_data(nla), alen, prefix + 1) else: dump_attr(ofd, nla, prefix) padlen = nla_padlen(alen) if padlen > 0: ofd('%s [PADDING] %d octets', prefix_whitespaces, padlen) dump_hex(ofd, bytearray_ptr(nla_data(nla), alen), padlen, prefix) if rem.value: ofd('%s [LEFTOVER] %d octets', prefix_whitespaces, rem)
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 test_repr(): """Test repr() of instances.""" assert 'c_byte(123)' == repr(c_byte(123)) if sys.maxsize > 2**32: # 64-bit. assert 'c_int(1234567890)' == repr(c_int(1234567890)) else: assert 'c_long(1234567890)' == repr(c_int(1234567890)).replace( 'L)', ')') assert 'c_byte(123)' == repr(c_int8(123)) assert 'c_long(1234567890)' == repr(c_long(1234567890)).replace('L)', ')') if sys.maxsize > 2**32: # 64-bit. assert 'c_long(1234567890123456789)' == repr( c_longlong(1234567890123456789)).replace('L)', ')') else: assert 'c_longlong(1234567890123456789)' == repr( c_longlong(1234567890123456789)).replace('L)', ')') assert 'c_ushort(12345)' == repr(c_uint16(12345)) if sys.maxsize > 2**32: # 64-bit. assert 'c_uint(1234567890)' == repr(c_uint32(1234567890)).replace( 'L)', ')') else: assert 'c_ulong(1234567890)' == repr(c_uint32(1234567890)).replace( 'L)', ')') if sys.maxsize > 2**32: # 64-bit. assert 'c_ulong(12345678901234567890)' == repr( c_uint64(12345678901234567890)).replace('L)', ')') else: assert 'c_ulonglong(12345678901234567890)' == repr( c_uint64(12345678901234567890)).replace('L)', ')') assert 'c_ubyte(123)' == repr(c_uint8(123)) assert 'c_ubyte(123)' == repr(c_ubyte(123)) if sys.maxsize > 2**32: # 64-bit. assert 'c_uint(1234567890)' == repr(c_uint(1234567890)).replace( 'L)', ')') else: assert 'c_ulong(1234567890)' == repr(c_uint(1234567890)).replace( 'L)', ')') assert 'c_ulong(1234567890)' == repr(c_ulong(1234567890)).replace( 'L)', ')') if sys.maxsize > 2**32: # 64-bit. assert 'c_ulong(12345678901234567890)' == repr( c_ulonglong(12345678901234567890)).replace('L)', ')') else: assert 'c_ulonglong(12345678901234567890)' == repr( c_ulonglong(12345678901234567890)).replace('L)', ')') assert 'c_ushort(12345)' == repr(c_ushort(12345))
def test_minimum(): """Test minimum valid integer value.""" assert -128 == c_byte.from_buffer(bytearray(c_byte(-128))).value assert -2147483648 == c_int.from_buffer(bytearray(c_int(-2147483648))).value assert -128 == c_int8.from_buffer(bytearray(c_int8(-128))).value if sys.maxsize > 2 ** 32: # 64-bit. assert -9223372036854775808 == c_long.from_buffer(bytearray(c_long(-9223372036854775808))).value else: assert -2147483648 == c_long.from_buffer(bytearray(c_long(-2147483648))).value assert -9223372036854775808 == c_longlong.from_buffer(bytearray(c_longlong(-9223372036854775808))).value
def callback(msg, arg): nlh = nlmsg_hdr(msg) iface = ifinfomsg(nlmsg_data(nlh)) hdr = IFLA_RTA(iface) remaining = c_int(nlh.nlmsg_len - NLMSG_LENGTH(iface.SIZEOF)) while RTA_OK(hdr, remaining): if hdr.rta_type == IFLA_IFNAME: arg[int(iface.ifi_index)] = str(get_string(RTA_DATA(hdr)).decode('ascii')) hdr = RTA_NEXT(hdr, remaining) return NL_OK
def test_minimum(): """Test minimum valid integer value.""" assert -128 == c_byte.from_buffer(bytearray(c_byte(-128))).value assert -2147483648 == c_int.from_buffer(bytearray( c_int(-2147483648))).value assert -128 == c_int8.from_buffer(bytearray(c_int8(-128))).value if sys.maxsize > 2**32: # 64-bit. assert -9223372036854775808 == c_long.from_buffer( bytearray(c_long(-9223372036854775808))).value else: assert -2147483648 == c_long.from_buffer(bytearray( c_long(-2147483648))).value assert -9223372036854775808 == c_longlong.from_buffer( bytearray(c_longlong(-9223372036854775808))).value
def test_zero(): """Test zero integer value.""" assert 0 == c_byte.from_buffer(bytearray(c_byte())).value assert 0 == c_int.from_buffer(bytearray(c_int())).value assert 0 == c_int8.from_buffer(bytearray(c_int8())).value assert 0 == c_long.from_buffer(bytearray(c_long())).value assert 0 == c_longlong.from_buffer(bytearray(c_longlong())).value assert 0 == c_uint16.from_buffer(bytearray(c_uint16())).value assert 0 == c_uint32.from_buffer(bytearray(c_uint32())).value assert 0 == c_uint64.from_buffer(bytearray(c_uint64())).value assert 0 == c_uint8.from_buffer(bytearray(c_uint8())).value assert 0 == c_ubyte.from_buffer(bytearray(c_ubyte())).value assert 0 == c_uint.from_buffer(bytearray(c_uint())).value assert 0 == c_ulong.from_buffer(bytearray(c_ulong())).value assert 0 == c_ulonglong.from_buffer(bytearray(c_ulonglong())).value assert 0 == c_ushort.from_buffer(bytearray(c_ushort())).value
def test_middle(): """Test with arbitrary positive value.""" assert 123 == c_byte.from_buffer(bytearray(c_byte(123))).value assert 1234567890 == c_int.from_buffer(bytearray(c_int(1234567890))).value assert 123 == c_int8.from_buffer(bytearray(c_int8(123))).value assert 1234567890 == c_long.from_buffer(bytearray(c_long(1234567890))).value assert 1234567890123456789 == c_longlong.from_buffer(bytearray(c_longlong(1234567890123456789))).value assert 12345 == c_uint16.from_buffer(bytearray(c_uint16(12345))).value assert 1234567890 == c_uint32.from_buffer(bytearray(c_uint32(1234567890))).value assert 12345678901234567890 == c_uint64.from_buffer(bytearray(c_uint64(12345678901234567890))).value assert 123 == c_uint8.from_buffer(bytearray(c_uint8(123))).value assert 123 == c_ubyte.from_buffer(bytearray(c_ubyte(123))).value assert 1234567890 == c_uint.from_buffer(bytearray(c_uint(1234567890))).value assert 1234567890 == c_ulong.from_buffer(bytearray(c_ulong(1234567890))).value assert 12345678901234567890 == c_ulonglong.from_buffer(bytearray(c_ulonglong(12345678901234567890))).value assert 12345 == c_ushort.from_buffer(bytearray(c_ushort(12345))).value
def nla_parse(tb, maxtype, head, len_, policy): """Create attribute index based on a stream of attributes. https://github.com/thom311/libnl/blob/libnl3_2_25/lib/attr.c#L242 Iterates over the stream of attributes and stores a pointer to each attribute in the index array using the attribute type as index to the array. Attribute with a type greater than the maximum type specified will be silently ignored in order to maintain backwards compatibility. If `policy` is not None, the attribute will be validated using the specified policy. Positional arguments: tb -- dictionary to be filled (maxtype+1 elements). maxtype -- maximum attribute type expected and accepted (integer). head -- first nlattr with more in its bytearray payload (nlattr class instance). len_ -- length of attribute stream (integer). policy -- dictionary of nla_policy class instances as values, with nla types as keys. Returns: 0 on success or a negative error code. """ rem = c_int() for nla in nla_for_each_attr(head, len_, rem): type_ = nla_type(nla) if type_ > maxtype: continue if policy: err = validate_nla(nla, maxtype, policy) if err < 0: return err if type_ in tb and tb[type_]: _LOGGER.debug( 'Attribute of type %d found multiple times in message, previous attribute is being ignored.', type_) tb[type_] = nla if rem.value > 0: _LOGGER.debug('netlink: %d bytes leftover after parsing attributes.', rem.value) return 0
def nla_find(head, len_, attrtype): """Find a single attribute in a stream of attributes. https://github.com/thom311/libnl/blob/libnl3_2_25/lib/attr.c#L323 Iterates over the stream of attributes and compares each type with the type specified. Returns the first attribute which matches the type. Positional arguments: head -- first nlattr with more in its bytearray payload (nlattr class instance). len_ -- length of attributes stream (integer). attrtype -- attribute type to look for (integer). Returns: Attribute found (nlattr class instance) or None. """ rem = c_int() for nla in nla_for_each_attr(head, len_, rem): if nla_type(nla) == attrtype: return nla return None
def nla_parse(tb, maxtype, head, len_, policy): """Create attribute index based on a stream of attributes. https://github.com/thom311/libnl/blob/libnl3_2_25/lib/attr.c#L242 Iterates over the stream of attributes and stores a pointer to each attribute in the index array using the attribute type as index to the array. Attribute with a type greater than the maximum type specified will be silently ignored in order to maintain backwards compatibility. If `policy` is not None, the attribute will be validated using the specified policy. Positional arguments: tb -- dictionary to be filled (maxtype+1 elements). maxtype -- maximum attribute type expected and accepted (integer). head -- first nlattr with more in its bytearray payload (nlattr class instance). len_ -- length of attribute stream (integer). policy -- dictionary of nla_policy class instances as values, with nla types as keys. Returns: 0 on success or a negative error code. """ rem = c_int() for nla in nla_for_each_attr(head, len_, rem): type_ = nla_type(nla) if type_ > maxtype: continue if policy: err = validate_nla(nla, maxtype, policy) if err < 0: return err if type_ in tb and tb[type_]: _LOGGER.debug('Attribute of type %d found multiple times in message, previous attribute is being ignored.', type_) tb[type_] = nla if rem.value > 0: _LOGGER.debug('netlink: %d bytes leftover after parsing attributes.', rem.value) return 0
def test_maximum_overflow(): """Test positive overflow value.""" assert -128 == c_byte(128).value assert -2147483648 == c_int(2147483648).value assert -128 == c_int8(128).value if sys.maxsize > 2 ** 32: # 64-bit. assert -9223372036854775808 == c_long(9223372036854775808).value else: assert -2147483648 == c_long(2147483648).value assert -9223372036854775808 == c_longlong(9223372036854775808).value assert 0 == c_uint16(65536).value assert 0 == c_uint32(4294967296).value assert 0 == c_uint64(18446744073709551616).value assert 0 == c_uint8(256).value assert 0 == c_ubyte(256).value assert 0 == c_uint(4294967296).value if sys.maxsize > 2 ** 32: # 64-bit. assert 0 == c_ulong(18446744073709551616).value else: assert 0 == c_ulong(4294967296).value assert 0 == c_ulonglong(18446744073709551616).value assert 0 == c_ushort(65536).value
def test_minimum_overflow_more(): """Test negative overflow value with even lower numbers.""" assert 27 == c_byte(-229).value assert 2147383647 == c_int(-2147583649).value assert 117 == c_int8(-139).value if sys.maxsize > 2 ** 32: # 64-bit. assert 9223372036814775807 == c_long(-9223372036894775809).value else: assert 2147483647 == c_long(-2147483649).value assert 9223372033854775807 == c_longlong(-9223372039854775809).value assert 65524 == c_uint16(-12).value assert 4294967283 == c_uint32(-13).value assert 18446744073709551602 == c_uint64(-14).value assert 241 == c_uint8(-15).value assert 240 == c_ubyte(-16).value assert 4294967279 == c_uint(-17).value if sys.maxsize > 2 ** 32: # 64-bit. assert 18446744073709551598 == c_ulong(-18).value else: assert 4294967277 == c_ulong(-19).value assert 18446744073709551598 == c_ulonglong(-18).value assert 65515 == c_ushort(-21).value
def test_maximum(): """Test maximum valid integer value.""" assert 127 == c_byte.from_buffer(bytearray(c_byte(127))).value assert 2147483647 == c_int.from_buffer(bytearray(c_int(2147483647))).value assert 127 == c_int8.from_buffer(bytearray(c_int8(127))).value if sys.maxsize > 2 ** 32: # 64-bit. assert 9223372036854775807 == c_long.from_buffer(bytearray(c_long(9223372036854775807))).value else: assert 2147483647 == c_long.from_buffer(bytearray(c_long(2147483647))).value assert 9223372036854775807 == c_longlong.from_buffer(bytearray(c_longlong(9223372036854775807))).value assert 65535 == c_uint16.from_buffer(bytearray(c_uint16(65535))).value assert 4294967295 == c_uint32.from_buffer(bytearray(c_uint32(4294967295))).value assert 18446744073709551615 == c_uint64.from_buffer(bytearray(c_uint64(18446744073709551615))).value assert 255 == c_uint8.from_buffer(bytearray(c_uint8(255))).value assert 255 == c_ubyte.from_buffer(bytearray(c_ubyte(255))).value assert 4294967295 == c_uint.from_buffer(bytearray(c_uint(4294967295))).value if sys.maxsize > 2 ** 32: # 64-bit. assert 18446744073709551615 == c_ulong.from_buffer(bytearray(c_ulong(18446744073709551615))).value else: assert 4294967295 == c_ulong.from_buffer(bytearray(c_ulong(4294967295))).value assert 18446744073709551615 == c_ulonglong.from_buffer(bytearray(c_ulonglong(18446744073709551615))).value assert 65535 == c_ushort.from_buffer(bytearray(c_ushort(65535))).value
def test_maximum_overflow_more(): """Test positive overflow value with even greater numbers.""" assert -118 == c_byte(138).value assert -2147482548 == c_int(2147484748).value assert -118 == c_int8(138).value if sys.maxsize > 2 ** 32: # 64-bit. assert -9223372036854775708 == c_long(9223372036854775908).value else: assert -2147483548 == c_long(2147483748).value assert -9223372036854775708 == c_longlong(9223372036854775908).value assert 100 == c_uint16(65636).value assert 100 == c_uint32(4294967396).value assert 100 == c_uint64(18446744073709551716).value assert 100 == c_uint8(356).value assert 90 == c_ubyte(346).value assert 100 == c_uint(4294967396).value if sys.maxsize > 2 ** 32: # 64-bit. assert 200 == c_ulong(18446744073709551816).value else: assert 1000 == c_ulong(4294968296).value assert 200 == c_ulonglong(18446744073709551816).value assert 10 == c_ushort(65546).value
def test_maximum_overflow(): """Test positive overflow value.""" assert -128 == c_byte(128).value assert -2147483648 == c_int(2147483648).value assert -128 == c_int8(128).value if sys.maxsize > 2**32: # 64-bit. assert -9223372036854775808 == c_long(9223372036854775808).value else: assert -2147483648 == c_long(2147483648).value assert -9223372036854775808 == c_longlong(9223372036854775808).value assert 0 == c_uint16(65536).value assert 0 == c_uint32(4294967296).value assert 0 == c_uint64(18446744073709551616).value assert 0 == c_uint8(256).value assert 0 == c_ubyte(256).value assert 0 == c_uint(4294967296).value if sys.maxsize > 2**32: # 64-bit. assert 0 == c_ulong(18446744073709551616).value else: assert 0 == c_ulong(4294967296).value assert 0 == c_ulonglong(18446744073709551616).value assert 0 == c_ushort(65536).value
def test_maximum_overflow_more(): """Test positive overflow value with even greater numbers.""" assert -118 == c_byte(138).value assert -2147482548 == c_int(2147484748).value assert -118 == c_int8(138).value if sys.maxsize > 2**32: # 64-bit. assert -9223372036854775708 == c_long(9223372036854775908).value else: assert -2147483548 == c_long(2147483748).value assert -9223372036854775708 == c_longlong(9223372036854775908).value assert 100 == c_uint16(65636).value assert 100 == c_uint32(4294967396).value assert 100 == c_uint64(18446744073709551716).value assert 100 == c_uint8(356).value assert 90 == c_ubyte(346).value assert 100 == c_uint(4294967396).value if sys.maxsize > 2**32: # 64-bit. assert 200 == c_ulong(18446744073709551816).value else: assert 1000 == c_ulong(4294968296).value assert 200 == c_ulonglong(18446744073709551816).value assert 10 == c_ushort(65546).value
def test_minimum_overflow(): """Test negative overflow value.""" assert 127 == c_byte(-129).value assert 2147483647 == c_int(-2147483649).value assert 127 == c_int8(-129).value if sys.maxsize > 2**32: # 64-bit. assert 9223372036854775807 == c_long(-9223372036854775809).value else: assert 2147483647 == c_long(-2147483649).value assert 9223372036854775807 == c_longlong(-9223372036854775809).value assert 65535 == c_uint16(-1).value assert 4294967295 == c_uint32(-1).value assert 18446744073709551615 == c_uint64(-1).value assert 255 == c_uint8(-1).value assert 255 == c_ubyte(-1).value assert 4294967295 == c_uint(-1).value if sys.maxsize > 2**32: # 64-bit. assert 18446744073709551615 == c_ulong(-1).value else: assert 4294967295 == c_ulong(-1).value assert 18446744073709551615 == c_ulonglong(-1).value assert 65535 == c_ushort(-1).value
def test_minimum_overflow_more(): """Test negative overflow value with even lower numbers.""" assert 27 == c_byte(-229).value assert 2147383647 == c_int(-2147583649).value assert 117 == c_int8(-139).value if sys.maxsize > 2**32: # 64-bit. assert 9223372036814775807 == c_long(-9223372036894775809).value else: assert 2147483647 == c_long(-2147483649).value assert 9223372033854775807 == c_longlong(-9223372039854775809).value assert 65524 == c_uint16(-12).value assert 4294967283 == c_uint32(-13).value assert 18446744073709551602 == c_uint64(-14).value assert 241 == c_uint8(-15).value assert 240 == c_ubyte(-16).value assert 4294967279 == c_uint(-17).value if sys.maxsize > 2**32: # 64-bit. assert 18446744073709551598 == c_ulong(-18).value else: assert 4294967277 == c_ulong(-19).value assert 18446744073709551598 == c_ulonglong(-18).value assert 65515 == c_ushort(-21).value
def test_minimum_overflow(): """Test negative overflow value.""" assert 127 == c_byte(-129).value assert 2147483647 == c_int(-2147483649).value assert 127 == c_int8(-129).value if sys.maxsize > 2 ** 32: # 64-bit. assert 9223372036854775807 == c_long(-9223372036854775809).value else: assert 2147483647 == c_long(-2147483649).value assert 9223372036854775807 == c_longlong(-9223372036854775809).value assert 65535 == c_uint16(-1).value assert 4294967295 == c_uint32(-1).value assert 18446744073709551615 == c_uint64(-1).value assert 255 == c_uint8(-1).value assert 255 == c_ubyte(-1).value assert 4294967295 == c_uint(-1).value if sys.maxsize > 2 ** 32: # 64-bit. assert 18446744073709551615 == c_ulong(-1).value else: assert 4294967295 == c_ulong(-1).value assert 18446744073709551615 == c_ulonglong(-1).value assert 65535 == c_ushort(-1).value
def test_middle(): """Test with arbitrary positive value.""" assert 123 == c_byte.from_buffer(bytearray(c_byte(123))).value assert 1234567890 == c_int.from_buffer(bytearray(c_int(1234567890))).value assert 123 == c_int8.from_buffer(bytearray(c_int8(123))).value assert 1234567890 == c_long.from_buffer(bytearray( c_long(1234567890))).value assert 1234567890123456789 == c_longlong.from_buffer( bytearray(c_longlong(1234567890123456789))).value assert 12345 == c_uint16.from_buffer(bytearray(c_uint16(12345))).value assert 1234567890 == c_uint32.from_buffer(bytearray( c_uint32(1234567890))).value assert 12345678901234567890 == c_uint64.from_buffer( bytearray(c_uint64(12345678901234567890))).value assert 123 == c_uint8.from_buffer(bytearray(c_uint8(123))).value assert 123 == c_ubyte.from_buffer(bytearray(c_ubyte(123))).value assert 1234567890 == c_uint.from_buffer(bytearray( c_uint(1234567890))).value assert 1234567890 == c_ulong.from_buffer(bytearray( c_ulong(1234567890))).value assert 12345678901234567890 == c_ulonglong.from_buffer( bytearray(c_ulonglong(12345678901234567890))).value assert 12345 == c_ushort.from_buffer(bytearray(c_ushort(12345))).value
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)
def test_nested(): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && ./a.out #include <netlink/msg.h> int main() { int i, rem1, rem2; struct nlattr *nla; struct nl_msg *msg = nlmsg_alloc(); struct nl_msg *sub = nlmsg_alloc(); struct nlmsghdr *nlh = nlmsg_hdr(sub); unsigned char *buf = (unsigned char *) nlh; nla_put_string(sub, 0, ""); nla_put_string(sub, 1, "Just tell me why!"); nla_put_string(sub, 2, "Please read this 55-page warrant."); nla_put_string(sub, 3, "There must be robots worse than I!"); nla_put_string(sub, 4, "We've checked around, there really aren't."); nlmsg_for_each_attr(nla, nlh, 0, rem1) { printf("type: %d len: %d; nla_get_string: %s\n", nla_type(nla), nla_len(nla), nla_get_string(nla)); } for (i = 0; i < nlmsg_total_size(nlmsg_datalen(nlh)); i++) printf("%02x", buf[i]); printf("\n"); nla_put_nested(msg, 5, sub); nlmsg_free(sub); sub = nlmsg_alloc(); nlh = nlmsg_hdr(sub); buf = (unsigned char *) nlh; nla_put_string(sub, 6, "Aw, don't blame me,"); nla_put_string(sub, 7, "Blame my upbringing!"); nlmsg_for_each_attr(nla, nlh, 0, rem1) { printf("type: %d len: %d; nla_get_string: %s\n", nla_type(nla), nla_len(nla), nla_get_string(nla)); } for (i = 0; i < nlmsg_total_size(nlmsg_datalen(nlh)); i++) printf("%02x", buf[i]); printf("\n"); nla_put_nested(msg, 8, sub); nlmsg_free(sub); nlh = nlmsg_hdr(msg); buf = (unsigned char *) nlh; nla_put_u16(msg, 9, 666); for (i = 0; i < nlmsg_total_size(nlmsg_datalen(nlh)); i++) printf("%02x", buf[i]); printf("\n"); struct nlattr *nla_outer; nlmsg_for_each_attr(nla_outer, nlh, 0, rem1) { if (nla_type(nla_outer) != 9) { printf("Outer type: %d len:%d\n", nla_type(nla_outer), nla_len(nla_outer)); nla_for_each_nested(nla, nla_outer, rem2) { printf("type: %d len: %d; nla_get_string: %s\n", nla_type(nla), nla_len(nla), nla_get_string(nla)); } } else { printf("t: %d l:%d; get_u16: %d\n", nla_type(nla_outer), nla_len(nla_outer), nla_get_u16(nla_outer)); } } nlmsg_free(msg); return 0; } // Expected output: // type: 0 len: 1; nla_get_string: // type: 1 len: 18; nla_get_string: Just tell me why! // type: 2 len: 34; nla_get_string: Please read this 55-page warrant. // type: 3 len: 35; nla_get_string: There must be robots worse than I! // type: 4 len: 43; nla_get_string: We've checked around, there really aren't. // b00000000000000000000000000000000500000000000000160001004a7573742074656c6c206d65207768792100000026000200506c65617 365207265616420746869732035352d706167652077617272616e742e000000270003005468657265206d75737420626520726f626f747320776 f727365207468616e20492100002f000400576527766520636865636b65642061726f756e642c207468657265207265616c6c79206172656e277 42e0000 // type: 6 len: 20; nla_get_string: Aw, don't blame me, // type: 7 len: 21; nla_get_string: Blame my upbringing! // 440000000000000000000000000000001800060041772c20646f6e277420626c616d65206d652c0019000700426c616d65206d79207570627 2696e67696e672100000000 // f4000000000000000000000000000000a40005000500000000000000160001004a7573742074656c6c206d652077687921000000260002005 06c65617365207265616420746869732035352d706167652077617272616e742e000000270003005468657265206d75737420626520726f626f7 47320776f727365207468616e20492100002f000400576527766520636865636b65642061726f756e642c207468657265207265616c6c7920617 2656e27742e0000380008001800060041772c20646f6e277420626c616d65206d652c0019000700426c616d65206d792075706272696e67696e6 72100000000060009009a020000 // Outer type: 5 len:160 // type: 0 len: 1; nla_get_string: // type: 1 len: 18; nla_get_string: Just tell me why! // type: 2 len: 34; nla_get_string: Please read this 55-page warrant. // type: 3 len: 35; nla_get_string: There must be robots worse than I! // type: 4 len: 43; nla_get_string: We've checked around, there really aren't. // Outer type: 8 len:52 // type: 6 len: 20; nla_get_string: Aw, don't blame me, // type: 7 len: 21; nla_get_string: Blame my upbringing! // t: 9 l:2; get_u16: 666 """ rem1, rem2 = c_int(), c_int() msg = nlmsg_alloc() sub = nlmsg_alloc() nlh = nlmsg_hdr(sub) libnl.attr.nla_put_string(sub, 0, b"") libnl.attr.nla_put_string(sub, 1, b"Just tell me why!") libnl.attr.nla_put_string(sub, 2, b"Please read this 55-page warrant.") libnl.attr.nla_put_string(sub, 3, b"There must be robots worse than I!") libnl.attr.nla_put_string(sub, 4, b"We've checked around, there really aren't.") actual = list() for nla in nlmsg_for_each_attr(nlh, 0, rem1): actual.append((libnl.attr.nla_type(nla), libnl.attr.nla_len(nla), libnl.attr.nla_get_string(nla))) expected = [ (0, 1, b""), (1, 18, b"Just tell me why!"), (2, 34, b"Please read this 55-page warrant."), (3, 35, b"There must be robots worse than I!"), (4, 43, b"We've checked around, there really aren't."), ] assert expected == actual expected = ( "b00000000000000000000000000000000500000000000000160001004a7573742074656c6c206d652077687921000000260002" "00506c65617365207265616420746869732035352d706167652077617272616e742e000000270003005468657265206d757374" "20626520726f626f747320776f727365207468616e20492100002f000400576527766520636865636b65642061726f756e642c" "207468657265207265616c6c79206172656e27742e0000" ) assert expected == "".join(format(c, "02x") for c in nlh.bytearray[: nlmsg_total_size(nlmsg_datalen(nlh))]) libnl.attr.nla_put_nested(msg, 5, sub) sub = nlmsg_alloc() nlh = nlmsg_hdr(sub) libnl.attr.nla_put_string(sub, 6, b"Aw, don't blame me,") libnl.attr.nla_put_string(sub, 7, b"Blame my upbringing!") actual = list() for nla in nlmsg_for_each_attr(nlh, 0, rem1): actual.append((libnl.attr.nla_type(nla), libnl.attr.nla_len(nla), libnl.attr.nla_get_string(nla))) expected = [(6, 20, b"Aw, don't blame me,"), (7, 21, b"Blame my upbringing!")] assert expected == actual expected = ( "440000000000000000000000000000001800060041772c20646f6e277420626c616d65206d652c0019000700426c616d65206d" "792075706272696e67696e672100000000" ) assert expected == "".join(format(c, "02x") for c in nlh.bytearray[: nlmsg_total_size(nlmsg_datalen(nlh))]) libnl.attr.nla_put_nested(msg, 8, sub) nlh = nlmsg_hdr(msg) libnl.attr.nla_put_u16(msg, 9, 666) expected = ( "f4000000000000000000000000000000a40005000500000000000000160001004a7573742074656c6c206d6520776879210000" "0026000200506c65617365207265616420746869732035352d706167652077617272616e742e00000027000300546865726520" "6d75737420626520726f626f747320776f727365207468616e20492100002f000400576527766520636865636b65642061726f" "756e642c207468657265207265616c6c79206172656e27742e0000380008001800060041772c20646f6e277420626c616d6520" "6d652c0019000700426c616d65206d792075706272696e67696e672100000000060009009a020000" ) assert expected == "".join(format(c, "02x") for c in nlh.bytearray[: nlmsg_total_size(nlmsg_datalen(nlh))]) actual = list() for nla_outer in nlmsg_for_each_attr(nlh, 0, rem1): if libnl.attr.nla_type(nla_outer) != 9: actual.append((libnl.attr.nla_type(nla_outer), libnl.attr.nla_len(nla_outer), b"Outer")) for nla in libnl.attr.nla_for_each_nested(nla_outer, rem2): actual.append((libnl.attr.nla_type(nla), libnl.attr.nla_len(nla), libnl.attr.nla_get_string(nla))) else: actual.append( (libnl.attr.nla_type(nla_outer), libnl.attr.nla_len(nla_outer), libnl.attr.nla_get_u16(nla_outer)) ) expected = [ (5, 160, b"Outer"), (0, 1, b""), (1, 18, b"Just tell me why!"), (2, 34, b"Please read this 55-page warrant."), (3, 35, b"There must be robots worse than I!"), (4, 43, b"We've checked around, there really aren't."), (8, 52, b"Outer"), (6, 20, b"Aw, don't blame me,"), (7, 21, b"Blame my upbringing!"), (9, 2, 666), ] assert expected == actual
def recvmsgs(sk, cb): """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/nl.c#L775. This is where callbacks are called. Positional arguments: sk -- Netlink socket (nl_sock class instance). cb -- callbacks (nl_cb class instance). Returns: Number of bytes received or a negative error code. """ multipart = 0 interrupted = 0 nrecv = 0 buf = bytearray() # nla is passed on to not only to nl_recv() but may also be passed to a function pointer provided by the caller # which may or may not initialize the variable. Thomas Graf. nla = sockaddr_nl() creds = ucred() while True: # This is the `goto continue_reading` implementation. _LOGGER.debug('Attempting to read from 0x%x', id(sk)) n = c_int(cb.cb_recv_ow(sk, nla, buf, creds) if cb.cb_recv_ow else nl_recv(sk, nla, buf, creds)) if n.value <= 0: return n.value _LOGGER.debug('recvmsgs(0x%x): Read %d bytes', id(sk), n.value) hdr = nlmsghdr(bytearray_ptr(buf)) while nlmsg_ok(hdr, n): _LOGGER.debug('recvmsgs(0x%x): Processing valid message...', id(sk)) msg = nlmsg_convert(hdr) nlmsg_set_proto(msg, sk.s_proto) nlmsg_set_src(msg, nla) if creds: raise NotImplementedError # nlmsg_set_creds(msg, creds) nrecv += 1 # Raw callback is the first, it gives the most control to the user and he can do his very own parsing. if cb.cb_set[NL_CB_MSG_IN]: err = nl_cb_call(cb, NL_CB_MSG_IN, msg) # NL_CB_CALL(cb, NL_CB_MSG_IN, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) if cb.cb_set[NL_CB_SEQ_CHECK]: # Sequence number checking. The check may be done by the user, otherwise a very simple check is applied # enforcing strict ordering. err = nl_cb_call(cb, NL_CB_SEQ_CHECK, msg) # NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) elif not sk.s_flags & NL_NO_AUTO_ACK: # Only do sequence checking if auto-ack mode is enabled. if hdr.nlmsg_seq != sk.s_seq_expect: if cb.cb_set[NL_CB_INVALID]: err = nl_cb_call(cb, NL_CB_INVALID, msg) # NL_CB_CALL(cb, NL_CB_INVALID, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) else: return -NLE_SEQ_MISMATCH if hdr.nlmsg_type in (NLMSG_DONE, NLMSG_ERROR, NLMSG_NOOP, NLMSG_OVERRUN): # We can't check for !NLM_F_MULTI since some Netlink users in the kernel are broken. sk.s_seq_expect += 1 _LOGGER.debug('recvmsgs(0x%x): Increased expected sequence number to %d', id(sk), sk.s_seq_expect) if hdr.nlmsg_flags & NLM_F_MULTI: multipart = 1 if hdr.nlmsg_flags & NLM_F_DUMP_INTR: if cb.cb_set[NL_CB_DUMP_INTR]: err = nl_cb_call(cb, NL_CB_DUMP_INTR, msg) # NL_CB_CALL(cb, NL_CB_DUMP_INTR, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) else: # We have to continue reading to clear all messages until a NLMSG_DONE is received and report the # inconsistency. interrupted = 1 if hdr.nlmsg_flags & NLM_F_ACK: # Other side wishes to see an ack for this message. if cb.cb_set[NL_CB_SEND_ACK]: err = nl_cb_call(cb, NL_CB_SEND_ACK, msg) # NL_CB_CALL(cb, NL_CB_SEND_ACK, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) if hdr.nlmsg_type == NLMSG_DONE: # Messages terminates a multipart message, this is usually the end of a message and therefore we slip # out of the loop by default. the user may overrule this action by skipping this packet. multipart = 0 if cb.cb_set[NL_CB_FINISH]: err = nl_cb_call(cb, NL_CB_FINISH, msg) # NL_CB_CALL(cb, NL_CB_FINISH, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) elif hdr.nlmsg_type == NLMSG_NOOP: # Message to be ignored, the default action is to skip this message if no callback is specified. The # user may overrule this action by returning NL_PROCEED. if cb.cb_set[NL_CB_SKIPPED]: err = nl_cb_call(cb, NL_CB_SKIPPED, msg) # NL_CB_CALL(cb, NL_CB_SKIPPED, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) else: hdr = nlmsg_next(hdr, n) continue elif hdr.nlmsg_type == NLMSG_OVERRUN: # Data got lost, report back to user. The default action is to quit parsing. The user may overrule this # action by retuning NL_SKIP or NL_PROCEED (dangerous). if cb.cb_set[NL_CB_OVERRUN]: err = nl_cb_call(cb, NL_CB_OVERRUN, msg) # NL_CB_CALL(cb, NL_CB_OVERRUN, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) else: return -NLE_DUMP_INTR if interrupted else -NLE_MSG_OVERFLOW elif hdr.nlmsg_type == NLMSG_ERROR: # Message carries a nlmsgerr. e = nlmsgerr(nlmsg_data(hdr)) if hdr.nlmsg_len < nlmsg_size(e.SIZEOF): # Truncated error message, the default action is to stop parsing. The user may overrule this action # by returning NL_SKIP or NL_PROCEED (dangerous). if cb.cb_set[NL_CB_INVALID]: err = nl_cb_call(cb, NL_CB_INVALID, msg) # NL_CB_CALL(cb, NL_CB_INVALID, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) else: return -NLE_DUMP_INTR if interrupted else -NLE_MSG_TRUNC elif e.error: # Error message reported back from kernel. if cb.cb_err: err = cb.cb_err(nla, e, cb.cb_err_arg) if err < 0: return -NLE_DUMP_INTR if interrupted else err elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else -nl_syserr2nlerr(e.error) else: return -NLE_DUMP_INTR if interrupted else -nl_syserr2nlerr(e.error) elif cb.cb_set[NL_CB_ACK]: err = nl_cb_call(cb, NL_CB_ACK, msg) # NL_CB_CALL(cb, NL_CB_ACK, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) else: # Valid message (not checking for MULTIPART bit to get along with broken kernels. NL_SKIP has no effect # on this. if cb.cb_set[NL_CB_VALID]: err = nl_cb_call(cb, NL_CB_VALID, msg) # NL_CB_CALL(cb, NL_CB_VALID, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) hdr = nlmsg_next(hdr, n) del buf[:] creds = None if multipart: # Multipart message not yet complete, continue reading. continue err = 0 if interrupted: return -NLE_DUMP_INTR if not err: err = nrecv return err
def recvmsgs(sk, cb): """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/nl.c#L775. This is where callbacks are called. Positional arguments: sk -- Netlink socket (nl_sock class instance). cb -- callbacks (nl_cb class instance). Returns: Number of bytes received or a negative error code. """ multipart = 0 interrupted = 0 nrecv = 0 buf = bytearray() # nla is passed on to not only to nl_recv() but may also be passed to a function pointer provided by the caller # which may or may not initialize the variable. Thomas Graf. nla = sockaddr_nl() creds = ucred() while True: # This is the `goto continue_reading` implementation. _LOGGER.debug('Attempting to read from 0x%x', id(sk)) n = c_int( cb.cb_recv_ow(sk, nla, buf, creds) if cb. cb_recv_ow else nl_recv(sk, nla, buf, creds)) if n.value <= 0: return n.value _LOGGER.debug('recvmsgs(0x%x): Read %d bytes', id(sk), n.value) hdr = nlmsghdr(bytearray_ptr(buf)) while nlmsg_ok(hdr, n): _LOGGER.debug('recvmsgs(0x%x): Processing valid message...', id(sk)) msg = nlmsg_convert(hdr) nlmsg_set_proto(msg, sk.s_proto) nlmsg_set_src(msg, nla) if creds: raise NotImplementedError # nlmsg_set_creds(msg, creds) nrecv += 1 # Raw callback is the first, it gives the most control to the user and he can do his very own parsing. if cb.cb_set[NL_CB_MSG_IN]: err = nl_cb_call(cb, NL_CB_MSG_IN, msg) # NL_CB_CALL(cb, NL_CB_MSG_IN, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) if cb.cb_set[NL_CB_SEQ_CHECK]: # Sequence number checking. The check may be done by the user, otherwise a very simple check is applied # enforcing strict ordering. err = nl_cb_call(cb, NL_CB_SEQ_CHECK, msg) # NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) elif not sk.s_flags & NL_NO_AUTO_ACK: # Only do sequence checking if auto-ack mode is enabled. if hdr.nlmsg_seq != sk.s_seq_expect: if cb.cb_set[NL_CB_INVALID]: err = nl_cb_call( cb, NL_CB_INVALID, msg) # NL_CB_CALL(cb, NL_CB_INVALID, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else ( err or nrecv) else: return -NLE_SEQ_MISMATCH if hdr.nlmsg_type in (NLMSG_DONE, NLMSG_ERROR, NLMSG_NOOP, NLMSG_OVERRUN): # We can't check for !NLM_F_MULTI since some Netlink users in the kernel are broken. sk.s_seq_expect += 1 _LOGGER.debug( 'recvmsgs(0x%x): Increased expected sequence number to %d', id(sk), sk.s_seq_expect) if hdr.nlmsg_flags & NLM_F_MULTI: multipart = 1 if hdr.nlmsg_flags & NLM_F_DUMP_INTR: if cb.cb_set[NL_CB_DUMP_INTR]: err = nl_cb_call( cb, NL_CB_DUMP_INTR, msg) # NL_CB_CALL(cb, NL_CB_DUMP_INTR, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) else: # We have to continue reading to clear all messages until a NLMSG_DONE is received and report the # inconsistency. interrupted = 1 if hdr.nlmsg_flags & NLM_F_ACK: # Other side wishes to see an ack for this message. if cb.cb_set[NL_CB_SEND_ACK]: err = nl_cb_call( cb, NL_CB_SEND_ACK, msg) # NL_CB_CALL(cb, NL_CB_SEND_ACK, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) if hdr.nlmsg_type == NLMSG_DONE: # Messages terminates a multipart message, this is usually the end of a message and therefore we slip # out of the loop by default. the user may overrule this action by skipping this packet. multipart = 0 if cb.cb_set[NL_CB_FINISH]: err = nl_cb_call(cb, NL_CB_FINISH, msg) # NL_CB_CALL(cb, NL_CB_FINISH, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) elif hdr.nlmsg_type == NLMSG_NOOP: # Message to be ignored, the default action is to skip this message if no callback is specified. The # user may overrule this action by returning NL_PROCEED. if cb.cb_set[NL_CB_SKIPPED]: err = nl_cb_call(cb, NL_CB_SKIPPED, msg) # NL_CB_CALL(cb, NL_CB_SKIPPED, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) else: hdr = nlmsg_next(hdr, n) continue elif hdr.nlmsg_type == NLMSG_OVERRUN: # Data got lost, report back to user. The default action is to quit parsing. The user may overrule this # action by retuning NL_SKIP or NL_PROCEED (dangerous). if cb.cb_set[NL_CB_OVERRUN]: err = nl_cb_call(cb, NL_CB_OVERRUN, msg) # NL_CB_CALL(cb, NL_CB_OVERRUN, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) else: return -NLE_DUMP_INTR if interrupted else -NLE_MSG_OVERFLOW elif hdr.nlmsg_type == NLMSG_ERROR: # Message carries a nlmsgerr. e = nlmsgerr(nlmsg_data(hdr)) if hdr.nlmsg_len < nlmsg_size(e.SIZEOF): # Truncated error message, the default action is to stop parsing. The user may overrule this action # by returning NL_SKIP or NL_PROCEED (dangerous). if cb.cb_set[NL_CB_INVALID]: err = nl_cb_call( cb, NL_CB_INVALID, msg) # NL_CB_CALL(cb, NL_CB_INVALID, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else ( err or nrecv) else: return -NLE_DUMP_INTR if interrupted else -NLE_MSG_TRUNC elif e.error: # Error message reported back from kernel. if cb.cb_err: err = cb.cb_err(nla, e, cb.cb_err_arg) if err < 0: return -NLE_DUMP_INTR if interrupted else err elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else -nl_syserr2nlerr( e.error) else: return -NLE_DUMP_INTR if interrupted else -nl_syserr2nlerr( e.error) elif cb.cb_set[NL_CB_ACK]: err = nl_cb_call(cb, NL_CB_ACK, msg) # NL_CB_CALL(cb, NL_CB_ACK, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) else: # Valid message (not checking for MULTIPART bit to get along with broken kernels. NL_SKIP has no effect # on this. if cb.cb_set[NL_CB_VALID]: err = nl_cb_call(cb, NL_CB_VALID, msg) # NL_CB_CALL(cb, NL_CB_VALID, msg) if err == NL_OK: pass elif err == NL_SKIP: hdr = nlmsg_next(hdr, n) continue elif err == NL_STOP: return -NLE_DUMP_INTR if interrupted else nrecv else: return -NLE_DUMP_INTR if interrupted else (err or nrecv) hdr = nlmsg_next(hdr, n) del buf[:] creds = None if multipart: # Multipart message not yet complete, continue reading. continue err = 0 if interrupted: return -NLE_DUMP_INTR if not err: err = nrecv return err
def ifi_index(self, value): """Index setter.""" self.bytearray[self._get_slicers(3)] = bytearray(c_int(value or 0))
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 test_nested(): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && ./a.out #include <netlink/msg.h> int main() { int i, rem1, rem2; struct nlattr *nla; struct nl_msg *msg = nlmsg_alloc(); struct nl_msg *sub = nlmsg_alloc(); struct nlmsghdr *nlh = nlmsg_hdr(sub); unsigned char *buf = (unsigned char *) nlh; nla_put_string(sub, 0, ""); nla_put_string(sub, 1, "Just tell me why!"); nla_put_string(sub, 2, "Please read this 55-page warrant."); nla_put_string(sub, 3, "There must be robots worse than I!"); nla_put_string(sub, 4, "We've checked around, there really aren't."); nlmsg_for_each_attr(nla, nlh, 0, rem1) { printf("type: %d len: %d; nla_get_string: %s\n", nla_type(nla), nla_len(nla), nla_get_string(nla)); } for (i = 0; i < nlmsg_total_size(nlmsg_datalen(nlh)); i++) printf("%02x", buf[i]); printf("\n"); nla_put_nested(msg, 5, sub); nlmsg_free(sub); sub = nlmsg_alloc(); nlh = nlmsg_hdr(sub); buf = (unsigned char *) nlh; nla_put_string(sub, 6, "Aw, don't blame me,"); nla_put_string(sub, 7, "Blame my upbringing!"); nlmsg_for_each_attr(nla, nlh, 0, rem1) { printf("type: %d len: %d; nla_get_string: %s\n", nla_type(nla), nla_len(nla), nla_get_string(nla)); } for (i = 0; i < nlmsg_total_size(nlmsg_datalen(nlh)); i++) printf("%02x", buf[i]); printf("\n"); nla_put_nested(msg, 8, sub); nlmsg_free(sub); nlh = nlmsg_hdr(msg); buf = (unsigned char *) nlh; nla_put_u16(msg, 9, 666); for (i = 0; i < nlmsg_total_size(nlmsg_datalen(nlh)); i++) printf("%02x", buf[i]); printf("\n"); struct nlattr *nla_outer; nlmsg_for_each_attr(nla_outer, nlh, 0, rem1) { if (nla_type(nla_outer) != 9) { printf("Outer type: %d len:%d\n", nla_type(nla_outer), nla_len(nla_outer)); nla_for_each_nested(nla, nla_outer, rem2) { printf("type: %d len: %d; nla_get_string: %s\n", nla_type(nla), nla_len(nla), nla_get_string(nla)); } } else { printf("t: %d l:%d; get_u16: %d\n", nla_type(nla_outer), nla_len(nla_outer), nla_get_u16(nla_outer)); } } nlmsg_free(msg); return 0; } // Expected output: // type: 0 len: 1; nla_get_string: // type: 1 len: 18; nla_get_string: Just tell me why! // type: 2 len: 34; nla_get_string: Please read this 55-page warrant. // type: 3 len: 35; nla_get_string: There must be robots worse than I! // type: 4 len: 43; nla_get_string: We've checked around, there really aren't. // b00000000000000000000000000000000500000000000000160001004a7573742074656c6c206d65207768792100000026000200506c65617 365207265616420746869732035352d706167652077617272616e742e000000270003005468657265206d75737420626520726f626f747320776 f727365207468616e20492100002f000400576527766520636865636b65642061726f756e642c207468657265207265616c6c79206172656e277 42e0000 // type: 6 len: 20; nla_get_string: Aw, don't blame me, // type: 7 len: 21; nla_get_string: Blame my upbringing! // 440000000000000000000000000000001800060041772c20646f6e277420626c616d65206d652c0019000700426c616d65206d79207570627 2696e67696e672100000000 // f4000000000000000000000000000000a40005000500000000000000160001004a7573742074656c6c206d652077687921000000260002005 06c65617365207265616420746869732035352d706167652077617272616e742e000000270003005468657265206d75737420626520726f626f7 47320776f727365207468616e20492100002f000400576527766520636865636b65642061726f756e642c207468657265207265616c6c7920617 2656e27742e0000380008001800060041772c20646f6e277420626c616d65206d652c0019000700426c616d65206d792075706272696e67696e6 72100000000060009009a020000 // Outer type: 5 len:160 // type: 0 len: 1; nla_get_string: // type: 1 len: 18; nla_get_string: Just tell me why! // type: 2 len: 34; nla_get_string: Please read this 55-page warrant. // type: 3 len: 35; nla_get_string: There must be robots worse than I! // type: 4 len: 43; nla_get_string: We've checked around, there really aren't. // Outer type: 8 len:52 // type: 6 len: 20; nla_get_string: Aw, don't blame me, // type: 7 len: 21; nla_get_string: Blame my upbringing! // t: 9 l:2; get_u16: 666 """ rem1, rem2 = c_int(), c_int() msg = nlmsg_alloc() sub = nlmsg_alloc() nlh = nlmsg_hdr(sub) libnl.attr.nla_put_string(sub, 0, b'') libnl.attr.nla_put_string(sub, 1, b'Just tell me why!') libnl.attr.nla_put_string(sub, 2, b'Please read this 55-page warrant.') libnl.attr.nla_put_string(sub, 3, b'There must be robots worse than I!') libnl.attr.nla_put_string(sub, 4, b"We've checked around, there really aren't.") actual = list() for nla in nlmsg_for_each_attr(nlh, 0, rem1): actual.append((libnl.attr.nla_type(nla), libnl.attr.nla_len(nla), libnl.attr.nla_get_string(nla))) expected = [ (0, 1, b''), (1, 18, b'Just tell me why!'), (2, 34, b'Please read this 55-page warrant.'), (3, 35, b'There must be robots worse than I!'), (4, 43, b"We've checked around, there really aren't."), ] assert expected == actual expected = ( 'b00000000000000000000000000000000500000000000000160001004a7573742074656c6c206d652077687921000000260002' '00506c65617365207265616420746869732035352d706167652077617272616e742e000000270003005468657265206d757374' '20626520726f626f747320776f727365207468616e20492100002f000400576527766520636865636b65642061726f756e642c' '207468657265207265616c6c79206172656e27742e0000') assert expected == ''.join( format(c, '02x') for c in nlh.bytearray[:nlmsg_total_size(nlmsg_datalen(nlh))]) libnl.attr.nla_put_nested(msg, 5, sub) sub = nlmsg_alloc() nlh = nlmsg_hdr(sub) libnl.attr.nla_put_string(sub, 6, b"Aw, don't blame me,") libnl.attr.nla_put_string(sub, 7, b'Blame my upbringing!') actual = list() for nla in nlmsg_for_each_attr(nlh, 0, rem1): actual.append((libnl.attr.nla_type(nla), libnl.attr.nla_len(nla), libnl.attr.nla_get_string(nla))) expected = [ (6, 20, b"Aw, don't blame me,"), (7, 21, b'Blame my upbringing!'), ] assert expected == actual expected = ( '440000000000000000000000000000001800060041772c20646f6e277420626c616d65206d652c0019000700426c616d65206d' '792075706272696e67696e672100000000') assert expected == ''.join( format(c, '02x') for c in nlh.bytearray[:nlmsg_total_size(nlmsg_datalen(nlh))]) libnl.attr.nla_put_nested(msg, 8, sub) nlh = nlmsg_hdr(msg) libnl.attr.nla_put_u16(msg, 9, 666) expected = ( 'f4000000000000000000000000000000a40005000500000000000000160001004a7573742074656c6c206d6520776879210000' '0026000200506c65617365207265616420746869732035352d706167652077617272616e742e00000027000300546865726520' '6d75737420626520726f626f747320776f727365207468616e20492100002f000400576527766520636865636b65642061726f' '756e642c207468657265207265616c6c79206172656e27742e0000380008001800060041772c20646f6e277420626c616d6520' '6d652c0019000700426c616d65206d792075706272696e67696e672100000000060009009a020000' ) assert expected == ''.join( format(c, '02x') for c in nlh.bytearray[:nlmsg_total_size(nlmsg_datalen(nlh))]) actual = list() for nla_outer in nlmsg_for_each_attr(nlh, 0, rem1): if libnl.attr.nla_type(nla_outer) != 9: actual.append((libnl.attr.nla_type(nla_outer), libnl.attr.nla_len(nla_outer), b'Outer')) for nla in libnl.attr.nla_for_each_nested(nla_outer, rem2): actual.append( (libnl.attr.nla_type(nla), libnl.attr.nla_len(nla), libnl.attr.nla_get_string(nla))) else: actual.append( (libnl.attr.nla_type(nla_outer), libnl.attr.nla_len(nla_outer), libnl.attr.nla_get_u16(nla_outer))) expected = [ (5, 160, b'Outer'), (0, 1, b''), (1, 18, b'Just tell me why!'), (2, 34, b'Please read this 55-page warrant.'), (3, 35, b'There must be robots worse than I!'), (4, 43, b"We've checked around, there really aren't."), (8, 52, b'Outer'), (6, 20, b"Aw, don't blame me,"), (7, 21, b'Blame my upbringing!'), (9, 2, 666), ] assert expected == actual