[PATCH v9 3/4] Netlink: handle multi netlink messages
Dmitry V. Levin
ldv at altlinux.org
Thu Jul 7 12:34:19 UTC 2016
On Wed, Jul 06, 2016 at 03:49:24PM +0000, Fabien Siron wrote:
> Handle the case where there are several messages in the buffer.
> This is very useful to some protocols like SOCK_DIAG.
>
> * netlink.c (fetch_nlmsg, next_nlmsg): New functions.
> (decode_netlink_msg): New function.
> (decode_netlink): Call decode_netlink_msg().
> * tests/netlink_parsing.c (send_query): Adapt test.
This is v9 but the code hasn't matured for the merge yet, and I'm getting
tired explaining its problems over and over again, so here is a kind of
commit I was expecting all this time, feel free to reuse it.
[PATCH] netlink: handle multipart netlink messages
Handle multipart netlink messages made of multiple struct nlmsghdr
headers with associated payload in one byte stream.
* netlink.c (fetch_nlmsghdr, print_nlmsghdr,
decode_nlmsghdr_with_payload): New functions.
(decode_netlink): Use them.
* tests/netlink_parsing.c (send_query): Check them.
---
netlink.c | 102 +++++++++++++++++++++++++++++++++++++++--------
tests/netlink_protocol.c | 94 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 179 insertions(+), 17 deletions(-)
diff --git a/netlink.c b/netlink.c
index c43f6e7..71573d4 100644
--- a/netlink.c
+++ b/netlink.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2016 Fabien Siron <fabien.siron at epita.fr>
+ * Copyright (c) 2016 Dmitry V. Levin <ldv at altlinux.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,34 +32,101 @@
#include "xlat/netlink_flags.h"
#include "xlat/netlink_types.h"
-void
-decode_netlink(struct tcb *tcp, unsigned long addr, unsigned long size)
+/*
+ * Fetch a struct nlmsghdr from the given address.
+ */
+static bool
+fetch_nlmsghdr(struct tcb *tcp, struct nlmsghdr *nlmsghdr,
+ const unsigned long addr, const unsigned long len)
{
- struct nlmsghdr nlmsghdr;
-
- if (size < sizeof(struct nlmsghdr)) {
- printstr(tcp, addr, size);
- return;
+ if (len < sizeof(struct nlmsghdr)) {
+ printstr(tcp, addr, len);
+ return false;
}
- if (umove_or_printaddr(tcp, addr, &nlmsghdr))
- return;
- tprintf("{{len=%u, type=", nlmsghdr.nlmsg_len);
+ if (umove_or_printaddr(tcp, addr, nlmsghdr))
+ return false;
+
+ return true;
+}
+
+static void
+print_nlmsghdr(struct tcb *tcp, const struct nlmsghdr *const nlmsghdr)
+{
+ /* print the whole structure regardless of its nlmsg_len */
+
+ tprintf("{len=%u, type=", nlmsghdr->nlmsg_len);
- printxval(netlink_types, nlmsghdr.nlmsg_type, "NLMSG_???");
+ printxval(netlink_types, nlmsghdr->nlmsg_type, "NLMSG_???");
tprints(", flags=");
- printflags(netlink_flags, nlmsghdr.nlmsg_flags, "NLM_F_???");
- /* manage get/new requests */
+ printflags(netlink_flags, nlmsghdr->nlmsg_flags, "NLM_F_???");
+
+ tprintf(", seq=%u, pid=%u}", nlmsghdr->nlmsg_seq,
+ nlmsghdr->nlmsg_pid);
+}
- tprintf(", seq=%u, pid=%u}", nlmsghdr.nlmsg_seq,
- nlmsghdr.nlmsg_pid);
+static void
+decode_nlmsghdr_with_payload(struct tcb *tcp,
+ const struct nlmsghdr *const nlmsghdr,
+ const unsigned long addr,
+ const unsigned long len)
+{
+ tprints("{");
+
+ print_nlmsghdr(tcp, nlmsghdr);
- if (size - sizeof(struct nlmsghdr) > 0) {
+ unsigned long nlmsg_len =
+ nlmsghdr->nlmsg_len > len ? len : nlmsghdr->nlmsg_len;
+ if (nlmsg_len > sizeof(struct nlmsghdr)) {
tprints(", ");
+
printstr(tcp, addr + sizeof(struct nlmsghdr),
- size - sizeof(struct nlmsghdr));
+ nlmsg_len - sizeof(struct nlmsghdr));
}
tprints("}");
}
+
+void
+decode_netlink(struct tcb *tcp, unsigned long addr, unsigned long len)
+{
+ struct nlmsghdr nlmsghdr;
+ bool print_array = false;
+ unsigned int elt;
+
+ for (elt = 0; fetch_nlmsghdr(tcp, &nlmsghdr, addr, len); elt++) {
+ if (abbrev(tcp) && elt == max_strlen) {
+ tprints("...");
+ break;
+ }
+
+ unsigned long nlmsg_len = NLMSG_ALIGN(nlmsghdr.nlmsg_len);
+ unsigned long next_addr = 0, next_len = 0;
+
+ if (nlmsghdr.nlmsg_len >= sizeof(struct nlmsghdr)) {
+ next_len = (len >= nlmsg_len) ? len - nlmsg_len : 0;
+
+ if (next_len && addr + nlmsg_len > addr)
+ next_addr = addr + nlmsg_len;
+ }
+
+ if (!print_array && next_addr) {
+ tprints("[");
+ print_array = true;
+ }
+
+ decode_nlmsghdr_with_payload(tcp, &nlmsghdr, addr, len);
+
+ if (!next_addr)
+ break;
+
+ tprints(", ");
+ addr = next_addr;
+ len = next_len;
+ }
+
+ if (print_array) {
+ tprints("]");
+ }
+}
diff --git a/tests/netlink_protocol.c b/tests/netlink_protocol.c
index 8afea59..e0d7b52 100644
--- a/tests/netlink_protocol.c
+++ b/tests/netlink_protocol.c
@@ -123,6 +123,100 @@ send_query(const int fd)
", seq=0, pid=0}, \"abcd\"}, %u, MSG_DONTWAIT, NULL, 0) = %u\n",
fd, req->nlh.nlmsg_len, NLM_F_DUMP,
(unsigned) sizeof(*req), (unsigned) sizeof(*req));
+
+ /* nlmsg_len < sizeof(struct nlmsghdr) */
+ req->nlh.nlmsg_len = 8;
+ if (sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0) != sizeof(*req))
+ perror_msg_and_skip("sendto");
+
+ printf("sendto(%d, {{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+ ", seq=0, pid=0}}, %u, MSG_DONTWAIT, NULL, 0) = %u\n",
+ fd, req->nlh.nlmsg_len, NLM_F_DUMP,
+ (unsigned) sizeof(*req), (unsigned) sizeof(*req));
+
+ /* a sequence of two nlmsg objects */
+ struct reqs {
+ struct req req1;
+ char padding[NLMSG_ALIGN(sizeof(struct req)) - sizeof(struct req)];
+ struct req req2;
+ } *const reqs = tail_alloc(sizeof(*reqs));
+ memcpy(&reqs->req1, &c_req, sizeof(c_req));
+ memcpy(&reqs->req2, &c_req, sizeof(c_req));
+
+ sendto(fd, reqs, sizeof(*reqs), MSG_DONTWAIT, NULL, 0);
+
+ printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+ ", seq=0, pid=0}, \"abcd\"}, {{len=%u, type=NLMSG_NOOP"
+ ", flags=NLM_F_REQUEST|0x%x, seq=0, pid=0}, \"abcd\"}]"
+ ", %u, MSG_DONTWAIT, NULL, 0) = %u\n",
+ fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP,
+ reqs->req2.nlh.nlmsg_len, NLM_F_DUMP,
+ (unsigned) sizeof(*reqs), (unsigned) sizeof(*reqs));
+
+ /* unfetchable second struct nlmsghdr */
+ void *const efault2 = tail_memdup(&reqs->req1, sizeof(reqs->req1));
+ sendto(fd, efault2, sizeof(*reqs), MSG_DONTWAIT, NULL, 0);
+
+ printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+ ", seq=0, pid=0}, \"abcd\"}, %p], %u, MSG_DONTWAIT, NULL, 0)"
+ " = -1 EFAULT (%m)\n",
+ fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP,
+ &((struct reqs *) efault2)->req2, (unsigned) sizeof(*reqs));
+
+ /* message length is not enough for the second struct nlmsghdr */
+ if (sendto(fd, reqs, sizeof(*reqs) - sizeof(req->nlh), MSG_DONTWAIT, NULL, 0)
+ != sizeof(*reqs) - sizeof(req->nlh))
+ perror_msg_and_skip("sendto");
+
+ printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+ ", seq=0, pid=0}, \"abcd\"}, \"",
+ fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP);
+ print_quoted_memory((void *) &reqs->req2.nlh,
+ sizeof(reqs->req2) - sizeof(req->nlh));
+ printf("\"], %u, MSG_DONTWAIT, NULL, 0) = %u\n",
+ (unsigned) (sizeof(*reqs) - sizeof(req->nlh)),
+ (unsigned) (sizeof(*reqs) - sizeof(req->nlh)));
+
+ /* second nlmsg_len < sizeof(struct nlmsghdr) */
+ reqs->req2.nlh.nlmsg_len = 4;
+ if (sendto(fd, reqs, sizeof(*reqs), MSG_DONTWAIT, NULL, 0)
+ != sizeof(*reqs))
+ perror_msg_and_skip("sendto");
+
+ printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+ ", seq=0, pid=0}, \"abcd\"}, {{len=%u, type=NLMSG_NOOP"
+ ", flags=NLM_F_REQUEST|0x%x, seq=0, pid=0}}], %u"
+ ", MSG_DONTWAIT, NULL, 0) = %u\n",
+ fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP,
+ reqs->req2.nlh.nlmsg_len, NLM_F_DUMP,
+ (unsigned) sizeof(*reqs), (unsigned) sizeof(*reqs));
+
+ /* abbreviated output */
+#define DEFAULT_STRLEN 32
+#define ABBREV_LEN (DEFAULT_STRLEN + 1)
+ const unsigned int msg_len = sizeof(struct nlmsghdr) * ABBREV_LEN;
+ struct nlmsghdr *const msgs = tail_alloc(msg_len);
+ unsigned int i;
+ for (i = 0; i < ABBREV_LEN; ++i) {
+ msgs[i].nlmsg_len = sizeof(*msgs);
+ msgs[i].nlmsg_type = NLMSG_NOOP;
+ msgs[i].nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+ msgs[i].nlmsg_seq = i;
+ msgs[i].nlmsg_pid = 0;
+ }
+
+ if (sendto(fd, msgs, msg_len, MSG_DONTWAIT, NULL, 0) != (int) msg_len)
+ perror_msg_and_skip("sendto");
+
+ printf("sendto(%d, [", fd);
+ for (i = 0; i < DEFAULT_STRLEN; ++i) {
+ if (i)
+ printf(", ");
+ printf("{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+ ", seq=%u, pid=0}}",
+ msgs[i].nlmsg_len, NLM_F_DUMP, msgs[i].nlmsg_seq);
+ }
+ printf(", ...], %u, MSG_DONTWAIT, NULL, 0) = %u\n", msg_len, msg_len);
}
int main(void)
--
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20160707/65ec487d/attachment.bin>
More information about the Strace-devel
mailing list