]> granicus.if.org Git - strace/commitdiff
netlink: add a basic socket diag parser of AF_INET and AF_INET6 messages
authorJingPiao Chen <chenjingpiao@gmail.com>
Tue, 13 Jun 2017 04:43:31 +0000 (12:43 +0800)
committerDmitry V. Levin <ldv@altlinux.org>
Thu, 15 Jun 2017 23:52:47 +0000 (23:52 +0000)
* defs.h (inet_protocols): New xlat prototype.
* linux/inet_diag.h (inet_diag_req): New structure.
(INET_DIAG_*): New enum.
* netlink_sock_diag.c: Include <arpa/inet.h>, <linux/inet_diag.h>
and "xlat/inet_diag_extended_flags.h".
(print_inet_diag_sockid, decode_inet_diag_req_compat)
(decode_inet_diag_req_v2, decode_inet_diag_req)
(decode_inet_diag_msg): New functions.
(diag_decoders): Add AF_INET and AF_INET6;
* xlat/inet_diag_extended_flags.in: New file.

Co-authored-by: Fabien Siron <fabien.siron@epita.fr>
defs.h
linux/inet_diag.h
netlink_sock_diag.c
xlat/inet_diag_extended_flags.in [new file with mode: 0644]

diff --git a/defs.h b/defs.h
index 9dbb643691b3fe18ee312001d8e22c480b3c1a20..487e51bd2c75658bac1f7fa9cdac59da25ce00c4 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -293,6 +293,7 @@ extern const struct xlat clocknames[];
 extern const struct xlat dirent_types[];
 extern const struct xlat ethernet_protocols[];
 extern const struct xlat evdev_abs[];
+extern const struct xlat inet_protocols[];
 extern const struct xlat msg_flags[];
 extern const struct xlat netlink_protocols[];
 extern const struct xlat open_access_modes[];
index 69012af0e12fff4f13bf6c01e841cdf0de258fff..245e4761683d450f7396db7ea4999cad4a921f4e 100644 (file)
@@ -14,7 +14,17 @@ struct inet_diag_sockid {
        uint32_t idiag_cookie[2];
 };
 
-/* Request structure */
+/* Request structures */
+struct inet_diag_req {
+       uint8_t idiag_family;
+       uint8_t idiag_src_len;
+       uint8_t idiag_dst_len;
+       uint8_t idiag_ext;
+       struct inet_diag_sockid id;
+       uint32_t idiag_states;
+       uint32_t idiag_dbs;
+};
+
 struct inet_diag_req_v2 {
        uint8_t sdiag_family;
        uint8_t sdiag_protocol;
@@ -40,4 +50,25 @@ struct inet_diag_msg {
        uint32_t idiag_inode;
 };
 
+/* Extensions */
+enum {
+       INET_DIAG_NONE,
+       INET_DIAG_MEMINFO,
+       INET_DIAG_INFO,
+       INET_DIAG_VEGASINFO,
+       INET_DIAG_CONG,
+       INET_DIAG_TOS,
+       INET_DIAG_TCLASS,
+       INET_DIAG_SKMEMINFO,
+       INET_DIAG_SHUTDOWN,
+       INET_DIAG_DCTCPINFO,
+       INET_DIAG_PROTOCOL,  /* response attribute only */
+       INET_DIAG_SKV6ONLY,
+       INET_DIAG_LOCALS,
+       INET_DIAG_PEERS,
+       INET_DIAG_PAD,
+       INET_DIAG_MARK,
+       INET_DIAG_BBRINFO,
+};
+
 #endif /* !STRACE_LINUX_INET_DIAG_H */
index 91749dd4e77c0f84b33f41d329c42421c35eb710..690a032af0580833b6dca11a181810874e5dd417 100644 (file)
 #include "defs.h"
 
 #include <sys/socket.h>
+#include <arpa/inet.h>
+#include <linux/inet_diag.h>
 #include <linux/netlink.h>
 #include <linux/netlink_diag.h>
 #include <linux/packet_diag.h>
 #include <linux/unix_diag.h>
 
+#include "xlat/inet_diag_extended_flags.h"
+
 #include "xlat/tcp_states.h"
 #include "xlat/tcp_state_flags.h"
 
@@ -267,6 +271,153 @@ decode_packet_diag_msg(struct tcb *const tcp,
        tprints("}");
 }
 
+static void
+print_inet_diag_sockid(const struct inet_diag_sockid *id, const uint8_t family)
+{
+       tprintf("{idiag_sport=htons(%u), idiag_dport=htons(%u)",
+               ntohs(id->idiag_sport), ntohs(id->idiag_dport));
+
+       tprints(", ");
+       print_inet_addr(family, id->idiag_src,
+                       sizeof(id->idiag_src), "idiag_src");
+       tprints(", ");
+       print_inet_addr(family, id->idiag_dst,
+                       sizeof(id->idiag_dst), "idiag_dst");
+
+       tprintf(", idiag_if=%" PRIu32
+               ", idiag_cookie=[%" PRIu32 ", %" PRIu32 "]}",
+               id->idiag_if, id->idiag_cookie[0], id->idiag_cookie[1]);
+}
+
+static void
+decode_inet_diag_req_compat(struct tcb *const tcp,
+                           const struct nlmsghdr *const nlmsghdr,
+                           const uint8_t family,
+                           const kernel_ulong_t addr,
+                           const kernel_ulong_t len)
+{
+       struct inet_diag_req req = { .idiag_family = family };
+       const size_t offset = sizeof(req.idiag_family);
+
+       tprints("{idiag_family=");
+       printxval(addrfams, req.idiag_family, "AF_???");
+
+       tprints(", ");
+       if (len >= sizeof(req)) {
+               if (!umoven_or_printaddr(tcp, addr + offset,
+                                        sizeof(req) - offset,
+                                        (void *) &req + offset)) {
+                       tprintf("idiag_src_len=%" PRIu8
+                               ", idiag_dst_len=%" PRIu8,
+                               req.idiag_src_len,
+                               req.idiag_dst_len);
+                       tprints(", idiag_ext=");
+                       printflags(inet_diag_extended_flags, req.idiag_ext,
+                                  "1<<INET_DIAG_\?\?\?-1");
+                       tprints(", id=");
+                       print_inet_diag_sockid(&req.id, req.idiag_family);
+                       tprints(", idiag_states=");
+                       printflags(tcp_state_flags, req.idiag_states,
+                                  "1<<TCP_???");
+                       tprintf(", idiag_dbs=%" PRIu32, req.idiag_dbs);
+               }
+       } else
+               tprints("...");
+       tprints("}");
+}
+
+static void
+decode_inet_diag_req_v2(struct tcb *const tcp,
+                       const struct nlmsghdr *const nlmsghdr,
+                       const uint8_t family,
+                       const kernel_ulong_t addr,
+                       const kernel_ulong_t len)
+{
+       struct inet_diag_req_v2 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)) {
+                       tprints("sdiag_protocol=");
+                       printxval(inet_protocols, req.sdiag_protocol,
+                                 "IPPROTO_???");
+                       tprints(", idiag_ext=");
+                       printflags(inet_diag_extended_flags, req.idiag_ext,
+                                  "1<<INET_DIAG_\?\?\?-1");
+                       tprints(", idiag_states=");
+                       printflags(tcp_state_flags, req.idiag_states,
+                                  "1<<TCP_???");
+                       tprints(", id=");
+                       print_inet_diag_sockid(&req.id, req.sdiag_family);
+               }
+       } else
+               tprints("...");
+       tprints("}");
+}
+
+static void
+decode_inet_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)
+{
+       if (nlmsghdr->nlmsg_type == TCPDIAG_GETSOCK
+           || nlmsghdr->nlmsg_type == DCCPDIAG_GETSOCK)
+               return decode_inet_diag_req_compat(tcp, nlmsghdr,
+                                                  family, addr, len);
+       else
+               return decode_inet_diag_req_v2(tcp, nlmsghdr,
+                                              family, addr, len);
+}
+
+static void
+decode_inet_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 inet_diag_msg msg = { .idiag_family = family };
+       const size_t offset = sizeof(msg.idiag_family);
+
+       tprints("{idiag_family=");
+       printxval(addrfams, msg.idiag_family, "AF_???");
+
+       tprints(", ");
+       if (len >= sizeof(msg)) {
+               if (!umoven_or_printaddr(tcp, addr + offset,
+                                        sizeof(msg) - offset,
+                                        (void *) &msg + offset)) {
+                       tprints("idiag_state=");
+                       printxval(tcp_states, msg.idiag_state, "TCP_???");
+                       tprintf(", idiag_timer=%" PRIu8
+                               ", idiag_retrans=%" PRIu8,
+                               msg.idiag_timer, msg.idiag_retrans);
+                       tprints(", id=");
+                       print_inet_diag_sockid(&msg.id, msg.idiag_family);
+                       tprintf(", idiag_expires=%" PRIu32
+                               ", idiag_rqueue=%" PRIu32
+                               ", idiag_wqueue=%" PRIu32
+                               ", idiag_uid=%" PRIu32
+                               ", idiag_inode=%" PRIu32,
+                               msg.idiag_expires,
+                               msg.idiag_rqueue,
+                               msg.idiag_wqueue,
+                               msg.idiag_uid,
+                               msg.idiag_inode);
+               }
+       } else
+               tprints("...");
+       tprints("}");
+}
+
 typedef void (*netlink_diag_decoder_t)(struct tcb *,
                                       const struct nlmsghdr *,
                                       uint8_t family,
@@ -276,6 +427,8 @@ typedef void (*netlink_diag_decoder_t)(struct tcb *,
 static const struct {
        const netlink_diag_decoder_t request, response;
 } diag_decoders[] = {
+       [AF_INET] = { decode_inet_diag_req, decode_inet_diag_msg },
+       [AF_INET6] = { decode_inet_diag_req, decode_inet_diag_msg },
        [AF_NETLINK] = { decode_netlink_diag_req, decode_netlink_diag_msg },
        [AF_PACKET] = { decode_packet_diag_req, decode_packet_diag_msg },
        [AF_UNIX] = { decode_unix_diag_req, decode_unix_diag_msg }
diff --git a/xlat/inet_diag_extended_flags.in b/xlat/inet_diag_extended_flags.in
new file mode 100644 (file)
index 0000000..05be3ca
--- /dev/null
@@ -0,0 +1,17 @@
+#unconditional
+1<<(INET_DIAG_MEMINFO-1)
+1<<(INET_DIAG_INFO-1)
+1<<(INET_DIAG_VEGASINFO-1)
+1<<(INET_DIAG_CONG-1)
+1<<(INET_DIAG_TOS-1)
+1<<(INET_DIAG_TCLASS-1)
+1<<(INET_DIAG_SKMEMINFO-1)
+1<<(INET_DIAG_SHUTDOWN-1)
+1<<(INET_DIAG_DCTCPINFO-1)
+1<<(INET_DIAG_PROTOCOL-1)
+1<<(INET_DIAG_SKV6ONLY-1)
+1<<(INET_DIAG_LOCALS-1)
+1<<(INET_DIAG_PEERS-1)
+1<<(INET_DIAG_PAD-1)
+1<<(INET_DIAG_MARK-1)
+1<<(INET_DIAG_BBRINFO-1)