[PATCH v8 3/4] Netlink: handle multi netlink messages
Fabien Siron
fabien.siron at epita.fr
Wed Jun 29 12:20:00 UTC 2016
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.
---
netlink.c | 87 ++++++++++++++++++++++++++++++++++++++++--------
tests/netlink_protocol.c | 19 ++++++++++-
2 files changed, 92 insertions(+), 14 deletions(-)
diff --git a/netlink.c b/netlink.c
index c43f6e7..77fb1d9 100644
--- a/netlink.c
+++ b/netlink.c
@@ -31,34 +31,95 @@
#include "xlat/netlink_flags.h"
#include "xlat/netlink_types.h"
-void
-decode_netlink(struct tcb *tcp, unsigned long addr, unsigned long size)
-{
- struct nlmsghdr nlmsghdr;
+/* since our target is not in the same process, here are some utils for nlmsg */
+static int
+fetch_nlmsg(struct tcb *tcp, struct nlmsghdr *nlmsghdr, unsigned long addr,
+ unsigned long len) {
+ if (addr == 0)
+ return 0;
+ if (len < sizeof(struct nlmsghdr)) {
+ if (len != 0)
+ printstr(tcp, addr, len);
+ return 0;
+ }
+
+ if (umove_or_printaddr(tcp, addr, nlmsghdr) == -1)
+ return 0;
+
+ return 1;
+}
+
+static unsigned long
+next_nlmsg(struct nlmsghdr *nlmsghdr, unsigned long addr, unsigned long *len) {
+ if (NLMSG_ALIGN(nlmsghdr->nlmsg_len) == 0 ||
+ NLMSG_ALIGN(nlmsghdr->nlmsg_len) > *len) {
+ *len = NLMSG_ALIGN(nlmsghdr->nlmsg_len);
+ return 0;
+ }
+ *len -= NLMSG_ALIGN(nlmsghdr->nlmsg_len);
+
+ if (addr + NLMSG_ALIGN(nlmsghdr->nlmsg_len) > addr) {
+ return addr + NLMSG_ALIGN(nlmsghdr->nlmsg_len);
+ } else {
+ *len = 0;
+ return 0;
+ }
+}
+
+static void
+decode_netlink_msg(struct tcb *tcp, struct nlmsghdr *nlmsghdr,
+ unsigned long addr, unsigned long size)
+{
if (size < sizeof(struct nlmsghdr)) {
printstr(tcp, addr, size);
return;
}
- if (umove_or_printaddr(tcp, addr, &nlmsghdr))
- return;
- tprintf("{{len=%u, type=", nlmsghdr.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_???");
+ printflags(netlink_flags, nlmsghdr->nlmsg_flags, "NLM_F_???");
/* manage get/new requests */
- tprintf(", seq=%u, pid=%u}", nlmsghdr.nlmsg_seq,
- nlmsghdr.nlmsg_pid);
+ tprintf(", seq=%u, pid=%u}", nlmsghdr->nlmsg_seq,
+ nlmsghdr->nlmsg_pid);
- if (size - sizeof(struct nlmsghdr) > 0) {
+ if (nlmsghdr->nlmsg_len - sizeof(struct nlmsghdr) > 0) {
tprints(", ");
+
printstr(tcp, addr + sizeof(struct nlmsghdr),
- size - sizeof(struct nlmsghdr));
+ nlmsghdr->nlmsg_len - sizeof(struct nlmsghdr));
}
tprints("}");
}
+
+void
+decode_netlink(struct tcb *tcp, unsigned long addr, unsigned long total_size) {
+ struct nlmsghdr nlmsghdr;
+ unsigned long elt, size = total_size;
+ int print_array = 0;
+
+ for (elt = 0; fetch_nlmsg(tcp, &nlmsghdr, addr, size);
+ addr = next_nlmsg(&nlmsghdr, addr, &size), elt++) {
+ if (elt == max_strlen && abbrev(tcp)) {
+ tprints("...");
+ break;
+ }
+ if (nlmsghdr.nlmsg_len < sizeof(struct nlmsghdr))
+ break;
+ if (size != total_size) {
+ tprints(", ");
+ } else if (NLMSG_ALIGN(nlmsghdr.nlmsg_len) < total_size) {
+ print_array = 1;
+ tprints("[");
+ }
+ decode_netlink_msg(tcp, &nlmsghdr, addr, size);
+ }
+ if (print_array) {
+ tprints("]");
+ }
+}
diff --git a/tests/netlink_protocol.c b/tests/netlink_protocol.c
index eb6a843..1434c2d 100644
--- a/tests/netlink_protocol.c
+++ b/tests/netlink_protocol.c
@@ -44,7 +44,7 @@
static void
send_query(const int fd)
{
- struct {
+ struct req {
struct nlmsghdr nlh;
char magic[4];
} req = {
@@ -55,6 +55,14 @@ send_query(const int fd)
},
.magic = "abcd"
};
+ struct {
+ struct req req1;
+ char padding[NLMSG_ALIGN(sizeof(req)) - sizeof(req)];
+ struct req req2;
+ } reqs = {
+ .req1 = req,
+ .req2 = req
+ };
const void *const efault = tail_alloc(sizeof(struct nlmsghdr) - 1);
@@ -91,6 +99,15 @@ send_query(const int fd)
printf("sendto(%d, %p, %u, MSG_DONTWAIT, NULL, 0) = -1 "
"EFAULT (%m)\n", fd, efault, (unsigned) sizeof(struct nlmsghdr));
+
+ 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, (unsigned) sizeof(req),
+ NLM_F_DUMP, (unsigned) sizeof(req), NLM_F_DUMP,
+ (unsigned) sizeof(reqs), (unsigned) sizeof(reqs));
}
int main(void)
--
2.9.0
More information about the Strace-devel
mailing list