def callback_recv_msg(msg, _): assert 16 == msg.nm_protocol assert 0 == msg.nm_flags assert 16 == msg.nm_src.nl_family assert 0 == msg.nm_src.nl_pid assert 0 == msg.nm_src.nl_groups assert 0 == msg.nm_dst.nl_family assert 0 == msg.nm_dst.nl_pid assert 0 == msg.nm_dst.nl_groups assert msg.nm_creds is None assert 16 == msg.nm_nlh.nlmsg_type assert 0 == msg.nm_nlh.nlmsg_flags assert 100 < msg.nm_nlh.nlmsg_pid assert 1000 < msg.nm_size assert 1 == msg.nm_refcnt dump_hex(logging.getLogger().debug, msg.nm_nlh.bytearray, nlmsg_datalen(msg.nm_nlh), 0) return NL_OK
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 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 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