]> granicus.if.org Git - strace/commitdiff
netlink: add a basic socket diag parser of AF_UNIX messages
authorDmitry V. Levin <ldv@altlinux.org>
Sat, 10 Jun 2017 22:07:54 +0000 (22:07 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Thu, 15 Jun 2017 00:30:47 +0000 (00:30 +0000)
* defs.h (socktypes): New xlat prototype.
* linux/unix_diag.h (UDIAG_SHOW_VFS, UDIAG_SHOW_ICONS, UDIAG_SHOW_RQLEN,
UDIAG_SHOW_MEMINFO): New macros.
* netlink_sock_diag.c: Include <sys/socket.h>, <linux/netlink.h>,
<linux/unix_diag.h>, "xlat/tcp_states.h", "xlat/tcp_state_flags.h",
and "xlat/unix_diag_show.h".
(decode_unix_diag_req, decode_unix_diag_msg): New functions.
(netlink_diag_decoder_t): New typedef.
(diag_decoders): New array.
(decode_netlink_sock_diag): Use it.
* xlat/tcp_state_flags.in: New file.
* xlat/tcp_states.in: Likewise.
* xlat/unix_diag_show.in: Likewise.

Co-authored-by: Fabien Siron <fabien.siron@epita.fr>
Co-authored-by: JingPiao Chen <chenjingpiao@gmail.com>
defs.h
linux/unix_diag.h
netlink_sock_diag.c
xlat/tcp_state_flags.in [new file with mode: 0644]
xlat/tcp_states.in [new file with mode: 0644]
xlat/unix_diag_show.in [new file with mode: 0644]

diff --git a/defs.h b/defs.h
index ddf80229053dccf3d10c139451de862c795d1c08..3b60d3d4dc30dd834a967bac76e08f3b8060b058 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -300,6 +300,7 @@ extern const struct xlat resource_flags[];
 extern const struct xlat setns_types[];
 extern const struct xlat sg_io_info[];
 extern const struct xlat socketlayers[];
+extern const struct xlat socktypes[];
 extern const struct xlat whence_codes[];
 
 /* Format of syscall return values */
index 0c3da5bb96c2a3824f68399496651d9ac810e607..a6b62bab0cca4dc08076eb09b1285cbe01df6479 100644 (file)
@@ -12,7 +12,11 @@ struct unix_diag_req {
 };
 
 #define UDIAG_SHOW_NAME                0x01
+#define UDIAG_SHOW_VFS         0x02
 #define UDIAG_SHOW_PEER                0x04
+#define UDIAG_SHOW_ICONS       0x08
+#define UDIAG_SHOW_RQLEN       0x10
+#define UDIAG_SHOW_MEMINFO     0x20
 
 struct unix_diag_msg {
        uint8_t  udiag_family;
index 29c09f3da49aed9021f70b2203f586b4d360a2eb..4687b119a84553d61503a625bdc8b70127274129 100644 (file)
 
 #include "defs.h"
 
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/unix_diag.h>
+
+#include "xlat/tcp_states.h"
+#include "xlat/tcp_state_flags.h"
+
+#include "xlat/unix_diag_show.h"
+
 static void
 decode_family(struct tcb *const tcp, const uint8_t family,
              const kernel_ulong_t addr, const kernel_ulong_t len)
@@ -43,6 +52,84 @@ decode_family(struct tcb *const tcp, const uint8_t family,
        tprints("}");
 }
 
+static void
+decode_unix_diag_req(struct tcb *const tcp,
+                    const struct nlmsghdr *const nlmsghdr,
+                    const uint8_t family,
+                    const kernel_ulong_t addr,
+                    const kernel_ulong_t len)
+{
+       struct unix_diag_req req = { .sdiag_family = family };
+       const size_t offset = sizeof(req.sdiag_family);
+
+       tprints("{sdiag_family=");
+       printxval(addrfams, req.sdiag_family, "AF_???");
+
+       tprints(", ");
+       if (len >= sizeof(req)) {
+               if (!umoven_or_printaddr(tcp, addr + offset,
+                                        sizeof(req) - offset,
+                                        (void *) &req + offset)) {
+                       tprintf("sdiag_protocol=%" PRIu8 ", udiag_states=",
+                               req.sdiag_protocol);
+                       printflags(tcp_state_flags, req.udiag_states,
+                                  "1<<TCP_???");
+                       tprintf(", udiag_ino=%" PRIu32 ", udiag_show=",
+                               req.udiag_ino);
+                       printflags(unix_diag_show, req.udiag_show,
+                                  "UDIAG_SHOW_???");
+                       tprintf(", udiag_cookie=[%" PRIu32 ", %" PRIu32 "]",
+                               req.udiag_cookie[0], req.udiag_cookie[1]);
+               }
+       } else
+               tprints("...");
+       tprints("}");
+}
+
+static void
+decode_unix_diag_msg(struct tcb *const tcp,
+                    const struct nlmsghdr *const nlmsghdr,
+                    const uint8_t family,
+                    const kernel_ulong_t addr,
+                    const kernel_ulong_t len)
+{
+       struct unix_diag_msg msg = { .udiag_family = family };
+       const size_t offset = sizeof(msg.udiag_family);
+
+       tprints("{udiag_family=");
+       printxval(addrfams, msg.udiag_family, "AF_???");
+
+       tprints(", ");
+       if (len >= sizeof(msg)) {
+               if (!umoven_or_printaddr(tcp, addr + offset,
+                                        sizeof(msg) - offset,
+                                        (void *) &msg + offset)) {
+                       tprints("udiag_type=");
+                       printxval(socktypes, msg.udiag_type, "SOCK_???");
+                       tprintf(", udiag_state=");
+                       printxval(tcp_states, msg.udiag_state, "TCP_???");
+                       tprintf(", udiag_ino=%" PRIu32
+                               ", udiag_cookie=[%" PRIu32 ", %" PRIu32 "]",
+                               msg.udiag_ino,
+                               msg.udiag_cookie[0], msg.udiag_cookie[1]);
+               }
+       } else
+               tprints("...");
+       tprints("}");
+}
+
+typedef void (*netlink_diag_decoder_t)(struct tcb *,
+                                      const struct nlmsghdr *,
+                                      uint8_t family,
+                                      kernel_ulong_t addr,
+                                      kernel_ulong_t len);
+
+static const struct {
+       const netlink_diag_decoder_t request, response;
+} diag_decoders[] = {
+       [AF_UNIX] = { decode_unix_diag_req, decode_unix_diag_msg }
+};
+
 bool
 decode_netlink_sock_diag(struct tcb *const tcp,
                         const struct nlmsghdr *const nlmsghdr,
@@ -51,8 +138,22 @@ decode_netlink_sock_diag(struct tcb *const tcp,
 {
        uint8_t family;
 
-       if (!umove_or_printaddr(tcp, addr, &family))
+       if (!umove_or_printaddr(tcp, addr, &family)) {
+               if (family < ARRAY_SIZE(diag_decoders)
+                   && len > sizeof(family)) {
+                       const netlink_diag_decoder_t decoder =
+                               (nlmsghdr->nlmsg_flags & NLM_F_REQUEST)
+                               ? diag_decoders[family].request
+                               : diag_decoders[family].response;
+
+                       if (decoder) {
+                               decoder(tcp, nlmsghdr, family, addr, len);
+                               return true;
+                       }
+               }
+
                decode_family(tcp, family, addr, len);
+       }
 
        return true;
 }
diff --git a/xlat/tcp_state_flags.in b/xlat/tcp_state_flags.in
new file mode 100644 (file)
index 0000000..8b63c15
--- /dev/null
@@ -0,0 +1,13 @@
+/* this file should be included after xlat/tcp_states.h */
+1<<TCP_ESTABLISHED
+1<<TCP_SYN_SENT
+1<<TCP_SYN_RECV
+1<<TCP_FIN_WAIT1
+1<<TCP_FIN_WAIT2
+1<<TCP_TIME_WAIT
+1<<TCP_CLOSE
+1<<TCP_CLOSE_WAIT
+1<<TCP_LAST_ACK
+1<<TCP_LISTEN
+1<<TCP_CLOSING
+1<<TCP_NEW_SYN_RECV
diff --git a/xlat/tcp_states.in b/xlat/tcp_states.in
new file mode 100644 (file)
index 0000000..287dc43
--- /dev/null
@@ -0,0 +1,12 @@
+TCP_ESTABLISHED                1
+TCP_SYN_SENT           2
+TCP_SYN_RECV           3
+TCP_FIN_WAIT1          4
+TCP_FIN_WAIT2          5
+TCP_TIME_WAIT          6
+TCP_CLOSE              7
+TCP_CLOSE_WAIT         8
+TCP_LAST_ACK           9
+TCP_LISTEN             10
+TCP_CLOSING            11
+TCP_NEW_SYN_RECV       12
diff --git a/xlat/unix_diag_show.in b/xlat/unix_diag_show.in
new file mode 100644 (file)
index 0000000..c7dbdfb
--- /dev/null
@@ -0,0 +1,6 @@
+UDIAG_SHOW_NAME
+UDIAG_SHOW_VFS
+UDIAG_SHOW_PEER
+UDIAG_SHOW_ICONS
+UDIAG_SHOW_RQLEN
+UDIAG_SHOW_MEMINFO